#include <stdio.h>

#include "../global.h"

#include "shared_survey_bar_graph.h"
#include "shared_survey_string.h"
#include "shared_survey_util.h"
#include "shared_survey_xml_parser.h"
#include "shared_record_parser.h"








static int 
contains_empty_response(RESULT *one_result)
{
   
    VALUE_COUNT *ptr;
    for(ptr = one_result->value_head; ptr; ptr = ptr->next)
	    if(atoi(ptr->value) == -1)
		    return 1;
    return 0;
}
		   
		   


static void
nl_to_space(char *string)
{
 char *ptr;
 
 for(ptr=string; *ptr; ptr++)
   if( (*ptr==10) || (*ptr == 13) || *ptr == '\'' || *ptr == '\"')
        *ptr = ' ';
}




   

void replace_quotes(char *str)
{
   int i, len;
   len = strlen(str);
   for(i = 0; i<len; i++)
   {
       if(str[i] == '\"' || str[i] == '\'')
	   str[i] = ' ';
   }
}





static 
void set_likert_choice_common_values(SURVEY_DATA *data,  int question_number, int steps,  char *question_type,  int bar_graph_count)
{
  #define MAX_TMP_NAME 50
  char name[MAX_TMP_NAME];

   snprintf(name, MAX_TMP_NAME, "survey.question.%d.type", bar_graph_count);
   cs_set_value(name, question_type);

   nl_to_space(data->caption);
   snprintf(name, MAX_TMP_NAME, "survey.question.%d.title", bar_graph_count);
   cs_set_value(name, data->caption);

   snprintf(name, MAX_TMP_NAME, "survey.question.%d.question_number", bar_graph_count);
   cs_set_int_value(name, question_number);
  #undef MAX_TMP_NAME 
}
   



static void
set_likert_values(SURVEY_DATA *likert, RESULT *one_result, int question_number, int bar_graph_count)
{
  #define MAX_TMP_NAME 50
   int i;
   int steps;
   char name[MAX_TMP_NAME];
   char tmp_value[MAX_TMP_NAME];
   int has_empty_responses =  contains_empty_response(one_result);
   
   steps = atoi(likert->steps_bgcolor);
   set_likert_choice_common_values(likert,   question_number,  steps, "likert", bar_graph_count);


   one_result->value_current = one_result->value_head;
   if(has_empty_responses)
       one_result->value_current = one_result->value_current->next;

   for(i =1; i<=steps; i++)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
      if(one_result->value_current && atoi(one_result->value_current->value)==i) 
      {
	    snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", (float)one_result->value_current->count/(float)one_result->count*100.0);
	    cs_set_value(name, tmp_value);
	    one_result->value_current = one_result->value_current->next;
      }
      else 
      {
	    snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", 0.0);
	    cs_set_value(name, tmp_value);
      }
   }
   if(has_empty_responses)
   {
       snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
       one_result->value_current = one_result->value_head;
       snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", (float)one_result->value_current->count/(float)one_result->count*100.0);
       cs_set_value(name, tmp_value);
   }
  snprintf(name, MAX_TMP_NAME, "survey.question.%d.number_choices", bar_graph_count);
  cs_set_int_value(name, has_empty_responses ? i: i-1);



   for(i =1; i<=steps; i++)
   {
       snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
       cs_set_int_value(name, i);
    }


   if(has_empty_responses)
   {
       snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
       cs_set_int_value(name, -1);
   }

	
   for(i = 0; i<steps; i++)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.legend.%d", bar_graph_count, i);
      if(i == 0)
      {
        nl_to_space(likert->left_cols);
	cs_set_value(name, likert->left_cols);
      }
      else if(i == steps -1)
      {
        nl_to_space(likert->right_rows);
	cs_set_value(name, likert->right_rows);

      }
      else
      {
	cs_set_value(name, "   ");
      }
   }
   if(has_empty_responses)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.noanswer", bar_graph_count);
      cs_set_int_value(name, 1);
   }


   one_result->value_current = one_result->value_head;
   if(has_empty_responses)
       one_result->value_current = one_result->value_current->next;

   for(i =1; i<=steps; i++)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
      if(one_result->value_current && atoi(one_result->value_current->value)==i) 
      {
          cs_set_int_value(name, one_result->value_current->count);
	  one_result->value_current = one_result->value_current->next;
      }
      else
        cs_set_int_value(name, 0);

   }

   if(has_empty_responses)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
       one_result->value_current = one_result->value_head;
      cs_set_int_value(name, one_result->value_current->count);
   }
#undef MAX_TMP_NAME 
}




static int 
get_choice_count(SURVEY_DATA *choice)
{
     int i = 0;
     choice->current = choice->head;
     while(choice->current)
     {
	 i++;
	 choice->current = choice->current->next;
     }
     return i;
}





static void
set_choice_values(SURVEY_DATA *choice, RESULT *one_result, int question_number, int bar_graph_count )
{
  #define MAX_TMP_NAME 100 
   int i =1;

   int has_empty_responses = contains_empty_response(one_result);
   int flag = get_choice_count(choice);
   char name[MAX_TMP_NAME];
   char tmp_value[MAX_TMP_NAME];
   
   if(strcmp(choice->steps_bgcolor, "yes") ==0)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.multi", bar_graph_count);
      cs_set_int_value(name, 1);
   }
	

   set_likert_choice_common_values(choice,   question_number,  flag, "multi_choice", bar_graph_count);
  


   one_result->value_current = one_result->value_head;

   if(has_empty_responses)
       one_result->value_current = one_result->value_current->next;
   choice->current = choice->head;
   while(choice->current )
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
	
     if(one_result->value_current && (atoi(one_result->value_current->value) == i))
     {
	    snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", ((float)one_result->value_current->count/(float)one_result->count) * 100.0);
	    cs_set_value(name, tmp_value);
            one_result->value_current = one_result->value_current->next;
     }
     else
     {
	    snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", 0.0);
	    cs_set_value(name, tmp_value);
     }
      i++;
      choice->current = choice->current->next;
   }

   if(has_empty_responses)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
      one_result->value_current = one_result->value_head;
      snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", ((float)one_result->value_current->count/(float)one_result->count) * 100.0);
      cs_set_value(name, tmp_value);
   }
  snprintf(name, MAX_TMP_NAME, "survey.question.%d.number_choices", bar_graph_count);
  cs_set_int_value(name, has_empty_responses ? i: i-1);
   

   for(i =1; i<=flag; i++)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
      cs_set_int_value(name, i);
   }

   if(has_empty_responses)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
      cs_set_int_value(name, -1);
   }

     
   
   i = 1;
   choice->current = choice->head;
   while(choice->current )
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.legend.%d", bar_graph_count, i-1);
      nl_to_space(choice->current->choice);
      cs_set_value(name, choice->current->choice);
      i++;
      choice->current = choice->current->next;
   }

   if(has_empty_responses)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.noanswer", bar_graph_count);
      cs_set_int_value(name, 1);
   }
   


   one_result->value_current = one_result->value_head;
   if(has_empty_responses)
       one_result->value_current = one_result->value_current->next;
   choice->current = choice->head;
   i =1;
   while(choice->current )
   {
     snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
     if(one_result->value_current && atoi(one_result->value_current->value) == i)
     {
	  cs_set_int_value(name, one_result->value_current->count);
          one_result->value_current = one_result->value_current->next;
     }
     else
	  cs_set_int_value(name, 0);
      i++;
      choice->current = choice->current->next;
   }

   if(has_empty_responses)
   {
      snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
      one_result->value_current = one_result->value_head;
      cs_set_int_value(name, one_result->value_current->count);
   }


#undef MAX_TMP_NAME 
}







static void
set_memo_values(SURVEY_DATA *memo, RESULT *one_result, int question_number, char *question_type, int element_number)
{
  #define MAX_TMP_NAME 50
   char name[MAX_TMP_NAME];
   int i =0;
   
   snprintf(name, MAX_TMP_NAME, "survey.question.%d.type", element_number);
   cs_set_value(name, question_type );
   snprintf(name, MAX_TMP_NAME, "survey.question.%d.title", element_number);
   cs_set_value(name, memo->caption);
   snprintf(name, MAX_TMP_NAME, "survey.question.%d.question_number", element_number);
   cs_set_int_value(name, question_number);

   one_result->value_current = one_result->value_head;
   while(one_result->value_current)
   {
       if(strcmp(one_result->value_current->value, "-1") == 0)
       {
         snprintf(name, MAX_TMP_NAME, "survey.question.%d.no_count", element_number);
         cs_set_int_value(name, one_result->value_current->count);
       }
       else
	{
         snprintf(name, MAX_TMP_NAME, "survey.question.%d.answer.%d", element_number, i);
          cs_set_value(name,  one_result->value_current->value);
         snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", element_number, i);
          cs_set_int_value(name,  one_result->value_current->count);
	  i++;
	}
       one_result->value_current = one_result->value_current->next;
   }
 #undef MAX_TMP_NAME 
}










static RESULT *
get_one_result(RECORD *list, int id)
{
    RESULT *ptr;
    ptr = list->head;
    while(ptr)
    {
       if(ptr->id == id )
	       return ptr;
       ptr = ptr->next;
    }
    return 0;
}



static int value_cmp(const char *a, const char *b)
{
   int value_a, value_b;

   if(!strcmp(a,b))
     return 0;
   if(!strcmp(a, "-1"))
     return -1;
   if(!strcmp(b,"-1"))
     return 1;
   value_a = atoi(a);
   value_b = atoi(b);
   if(value_a >value_b)
	return 1;
   return -1;
}




static RESULT *
sort_one_result(RESULT *one)
{
   VALUE_COUNT  *q, *tail, *p, *r;
   if (one->value_head != NULL)
   {
       tail = one->value_head;
       while (tail->next)
       {
          q = tail->next;
          if (value_cmp (q->value, one->value_head->value) < 0) 
          {
              tail->next = q->next;
              q->next = one->value_head;
              one->value_head = q;
	      
           }
           else
           {
              r = one->value_head;
              p = r->next;
              while (value_cmp (q->value, p->value) > 0) 
              {
                 r = p;
                 p = r->next;
              }
              if (q == p)
                tail = q;
              else
              {
                 tail->next = q->next;
                 q->next = p;
                 r->next = q;
              }
           }
       }
    }
   return one;
}




static RECORD *
sort_value_list(RECORD * list)
{
      list->current = list->head;
      while(list->current)
      {
	 list->current = sort_one_result(list->current);
	 list->current = list->current->next;
      }
      return list;
}
	   
	   
	   
static void
set_response_rate_title(SURVEY_DATA *data, RECORD *list, int number_takers)
{
   float response_rate;
   char tmp_value[MAX_PATH +1];
   char server_string[MAX_PATH +1];

   list->current = list->head;

   get_server_string(server_string, MAX_PATH);
   cs_set_value("survey.server_string", server_string); 

    cs_set_int_value("survey.num_response", list->current->count); 
   
   /* print number of people who could have taken the survey */   
   if(number_takers ==  -1)
   {
     cs_set_int_value("survey.num_expect_takers", list->expect_takers); 
     response_rate = (float) list->current->count/list->expect_takers;
   }
   else if(number_takers > 0)
   {
     cs_set_int_value("survey.num_expect_takers", number_takers); 
     response_rate = (float)list->current->count/number_takers;
   }   
      
   snprintf(tmp_value, MAX_PATH +1, "%.1f%%", response_rate * 100.0);
   cs_set_value("survey.rate", tmp_value); 
   cs_set_value("survey.title", data->caption); 


}






static 
void set_title_element(SURVEY_LIST *list, RECORD *record_list, int number_takers)
{
  int found = 0;
  
      for(list->current = list->head; list->current && !found; list->current=list->current->next)
      {
        found = !strcmp(list->current->tag_name, "title");
        if(found)
	      set_response_rate_title(list->current, record_list, number_takers);
      }

}


static 
void set_bar_graphs(SURVEY_LIST *list, RECORD *record_list, int *bar_graph_count)
{
  int question_number = 0;
  RESULT *ptr;


  
  *bar_graph_count = 0;  
  for(list->current = list->head; list->current; list->current=list->current->next)
      {
        if(strcmp(list->current->tag_name, "title") !=0 && strcmp(list->current->tag_name, "custom") != 0)
            question_number++;


        /** is_likert_tag() is in shared_survey_util.c ***/
        if(is_likert_tag(list->current->tag_name) ||
	                 !strcmp(list->current->tag_name, "choice") )
         {
             ptr = get_one_result(record_list, list->current->id); 
	     if(ptr)
	     {
               if(is_likert_tag(list->current->tag_name))
	           set_likert_values(list->current, ptr, question_number, *bar_graph_count);
               else
	           set_choice_values(list->current, ptr, question_number, *bar_graph_count);
	       (*bar_graph_count)++;
             }
        }        
     }        
}




static void
set_text_responses(SURVEY_LIST *list, RECORD *record_list, int bar_graph_count)
{
  int question_number = 0;
  RESULT *ptr;
  int element_number;
  
      element_number = bar_graph_count;
  
      for(list->current = list->head; list->current; list->current=list->current->next)
      {
        if(strcmp(list->current->tag_name, "title") != 0 && strcmp(list->current->tag_name, "custom") != 0)
            question_number++;


        if(!strcmp(list->current->tag_name, "memo") ||
	                 !strcmp(list->current->tag_name, "text") )
         {
             ptr = get_one_result(record_list, list->current->id); 
	     if(ptr)
	      {
	       set_memo_values(list->current, ptr, question_number,
	                            !strcmp(list->current->tag_name, "memo")?"memo":"short-answer", 
	                            element_number);
	       element_number++;
	      }    
        }        
     }        

}


static int find_value_in_list(VALUE_COUNT *v_head, char *temp, int count)
{
    VALUE_COUNT *ptr;
    for(ptr = v_head; ptr; ptr = ptr->next)
    {
	if(strcmp(ptr->value, temp) ==0)
	{
		ptr->count = ptr->count +count;
		return 1;
	}
    }
    return 0;
}

static VALUE_COUNT *add_node(char *new_value, VALUE_COUNT *head, int count)
{
      VALUE_COUNT *ptr, *current;

       ptr = (VALUE_COUNT *)malloc(sizeof(VALUE_COUNT));
       if(!ptr)
           cs_critical_error(ERR_MALLOC_FAILED, "shared_survey_bar_graph");
	ptr->value = malloc_str(new_value);
	ptr->count = count;
	ptr->next =0;

	if(!head)
	      head = ptr;
	else
	{
	    current = head;
	    while(current->next)
	    {
		current = current->next;
	    }
	    current->next = ptr;  
	}
       return head;	
}

static void parse_value(char *temp, char *new_value)
{
    char *ptr;

    ptr = strchr(temp, '|');
    if(!ptr)
      cs_critical_error(ERR_SURVEY_PARSE_DATA_FAILED, "Shared_survey_bar_graph");
    *ptr = '\0';
    strncpy(new_value, temp, MAX_PATH +1);
    ptr++;
    strncpy(temp, ptr, MAX_PATH +1);
		     
}


static int  get_number_data_fields(char *temp)
{
    int count =0, len =0, i;

    len = strlen(temp);
    for(i =0; i<len; i++)
    {
	if(temp[i] == '|')
	    count++;
    } 
    return count;
}

static void free_value_count(VALUE_COUNT *head)
{
   VALUE_COUNT *ptr;

   while(head)
   {
       ptr = head->next;
       if(head->value)
	     free(head->value);
       free(head);
       head = ptr;
   }
}


static VALUE_COUNT *get_new_value_list(VALUE_COUNT *old)
{
   VALUE_COUNT *v_head =0, *v_ptr;
   char temp[MAX_PATH +1];
   char new_value[MAX_PATH +1];
   int count =0, found =0, i;

    for(v_ptr = old; v_ptr; v_ptr = v_ptr->next)
    {
         strncpy(temp, v_ptr->value, MAX_PATH +1);
         count = get_number_data_fields(temp);
	 if(count > 1)
	 {
	     for(i = 0; i<count-1; i++)
	     {
		 found =0;
		 parse_value(temp, new_value);
		 if(v_head)
		   found = find_value_in_list(v_head, new_value, v_ptr->count);
			 
	          if(!found)
                       v_head = add_node(new_value, v_head, v_ptr->count);
	     }

	     found =0;
	     temp[strlen(temp) -1] = '\0';
	     if(v_head)
	         found = find_value_in_list(v_head, temp, v_ptr->count);

	     if(!found)
                  v_head = add_node(temp, v_head, v_ptr->count);


	    }
	    else
	    {
	        found = 0;
	        temp[strlen(temp)-1] = '\0';
	        if(v_head)
			 found = find_value_in_list(v_head, temp, v_ptr->count);

	        if(!found)
                      v_head = add_node(temp, v_head, v_ptr->count);
	    }	
     }
    return v_head;
}

RECORD * parse_multi_select_data(RECORD *re_list, int id)
{
     RESULT *ptr;
     VALUE_COUNT  *v_head =0;

     for(ptr = re_list->head; ptr; ptr = ptr->next)
     {
	  if(id == ptr->id)
	  {
             v_head = get_new_value_list(ptr->value_head);
	     if(v_head)
	     {
	        free_value_count(ptr->value_head);
	        ptr->value_head = v_head;
	     }
	  }
     }
     return re_list;
}


static void check_multi_choice_answers(SURVEY_LIST *list, RECORD *re_list)
{
   SURVEY_DATA *ptr;

   for(ptr = list->head; ptr;ptr = ptr->next)
   {
	if(strcmp(ptr->tag_name, "choice") ==0 && strcmp(ptr->steps_bgcolor, "yes") ==0)
	{
	    re_list = parse_multi_select_data(re_list, ptr->id);
	}
   }
}





int
set_survey_graph_results(  char *survey_fname,  char *survey_result_fname, int number_takers)
{
    SURVEY_LIST  *list;
    RECORD *record_list;
    int results_found = 0;
    int bar_graph_count = 0;
   
    list = survey_data_parser(survey_fname);   /* shared_survey_xml_parser.c */
    record_list = record_parser(survey_result_fname);   /* shared_record_parser.c */
    if(record_list->head)
    {
      check_multi_choice_answers(list, record_list);
      record_list = sort_value_list(record_list);

      set_title_element(list, record_list, number_takers);
      set_bar_graphs(list,record_list, &bar_graph_count);
      set_text_responses(list,record_list, bar_graph_count);      
      results_found = 1;
    }

    free_record_list(record_list);
    free_survey_data_list(list);
    return results_found;

}

