#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include "ClearSilver.h"
#include "sqlite3.h"
#include "global.h"
#include "custom.h"		/* for date FORMAT strings */
#include "grade.h"		/* for date FORMAT strings */
#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_grade_book_menu.h"
#include "manhat-lib/shared_grade_book_db.h"
#include "manhat-lib/shared_grade_book_util.h"
#include "manhat-lib/shared_grade_book_calculation_util.h"
#include "manhat-lib/shared_person_list.h"

void
read_parameters ( char *course, char *key, int *save_opt)
{
     char temp[MAX_PATH +1];

     cs_get_required_parameter("crs", course, MAX_PATH);
     cs_get_required_parameter("id", key, MAX_KEY);
     cs_get_required_parameter("save_option", temp, MAX_PATH);
     if(strcmp(temp, "no") == 0)
	   *save_opt =0;
     else if(strcmp(temp, "tab") == 0)
	   *save_opt =1;
     else if(strcmp(temp, "csv") == 0)
	   *save_opt =2;

}



void get_all_grades(CONFIG_STRUCT *conf)	
{
    if(global_item_list && global_item_list->head)
    {
	for(global_item_list->current = global_item_list->head; global_item_list->current; global_item_list->current = global_item_list->current->next)
	{
	   if(strcmp(global_item_list->current->grade_entered, "yes") ==0)
	   {
	
	       get_one_item_grade_list(conf, global_item_list->current->item_id, GRADE_BOOK_DB); /* shared_grade_book_db.h */
	       if(global_grade_temp_list && global_grade_temp_list->head)
	       {
		  
		   if(strcmp(global_item_list->current->is_letter_grade, "yes") == 0)
			 update_letter_log_list(conf,  global_item_list->current->item_id, GRADE_BOOK_DB, global_grade_temp_list);  /* shared_grade_book_db.h */

	               global_item_list->current->grades = global_grade_temp_list;
	       }

	   }
	}
    }
}

void send_heading(int save_opt)
{
    ITEM *ptr;
    printf ("Content-type:application/octet-stream\n");
    printf("Content-disposition:attachment; filename=\"%s\"\n\n", "grade_data_file.txt");

    if(save_opt == 1)
	fprintf(stdout, "%s\t%s\t", "Id", "Name");
    else
	fprintf(stdout, "\"%s\",\"%s\",", "Id", "Name");

    for(ptr = global_item_list->head; ptr; ptr = ptr->next)
    {
        if(save_opt == 1)
	    fprintf(stdout, "%s\t", ptr->item_name);
	else
	    fprintf(stdout, "\"%s\",", ptr->item_name);
    }
    if(save_opt == 1)
    {
	fprintf(stdout, "%s\t", "Total");
	fprintf(stdout, "%s\n", "Grade");
    }
    else
    {
	fprintf(stdout, "\"%s\",", "Total");
	fprintf(stdout, "\"%s\"\n", "Grade");
    }

}

void  print_total_grade_for_one_student(TOTAL_GRADE *std_grade, const char *username, int save_opt)  
{
    TOTAL_GRADE *ptr;
    int found = 0;



    for(ptr = std_grade; ptr && !found; ptr = ptr->next)
    {
	 if(strcmp(ptr->username, username) ==0)
	 {
              if(save_opt == 1)
              {
		 if(ptr->total >= 0)
		 {
	           fprintf(stdout, "%4.2f\t", ptr->total);
	           fprintf(stdout, "%s\n", ptr->grade);
		 }
		 else
		 {
	           fprintf(stdout, " \t" );
	           fprintf(stdout, " \n");
		 }
              }
              else
              {
		 if(ptr->total >= 0)
		 {
	          fprintf(stdout, "\"%4.2f\",", ptr->total);
	          fprintf(stdout, "\"%s\"\n", ptr->grade);
		 }
		 else
		 {
	          fprintf(stdout, "\" \",");
	          fprintf(stdout, "\" \"\n");
		 }
              }
	      found = 1;
	     
	 }
    }
    if(!found)
    {
	        if(save_opt == 1)
		{
	              fprintf(stdout, "%s\t", "na");
	              fprintf(stdout, "%s\n", "na");
		}
                else
		{
	              fprintf(stdout, "\"%s\",", "na");
	              fprintf(stdout, "\"%s\"\n", "na");
		}
    }
}

void  find_max_min_avg(TOTAL_GRADE *std_grade, double *max, double *min, double *avg, 
		 char *min_letter, char *max_letter, char *avg_letter)
{
   TOTAL_GRADE *ptr;
   double temp_total =0;
   double temp_max =-1;
   double temp_min =999999;
   double temp_avg =0;
   int count =0;

    for(ptr = std_grade; ptr; ptr = ptr->next)
    {
	if(ptr->total >=0)
	{
	temp_total += ptr->total;
	if(temp_max < ptr->total)
           temp_max = ptr->total;
	if(temp_min > ptr->total)
	    temp_min = ptr->total;
      count++;
       }	
    }

   if(count >0 && temp_total >= 0)
   {
   temp_avg = temp_total/(float)count; 
   
   *max = global_grade_conf.rounding_method == WHOLE_NUMBER ? whole_number(temp_max): nearest_tenth(temp_max);
   *min = global_grade_conf.rounding_method == WHOLE_NUMBER ? whole_number(temp_min): nearest_tenth(temp_min);
   *avg = global_grade_conf.rounding_method == WHOLE_NUMBER ? whole_number(temp_avg): nearest_tenth(temp_avg);

   get_one_student_grade(*max, max_letter);
   get_one_student_grade(*avg, avg_letter);
   get_one_student_grade(*min, min_letter);
   }
   else
   {
       *max = -9999;
       *avg = -9999;
       *min = -9999;
       
   }

}


void  print_max_min_avg(TOTAL_GRADE *std_grade, int save_opt)
{
    double max, min, avg;
    char avg_letter[MAX_GRADE_LEN +1];
    char min_letter[MAX_GRADE_LEN +1];
    char max_letter[MAX_GRADE_LEN +1];
    ITEM *ptr;
    
    find_max_min_avg(std_grade, &max, &min, &avg,  min_letter, max_letter, avg_letter);
    if(save_opt == 1)
      fprintf(stdout, "%s\t%s\t", "", "Min");
    else
      fprintf(stdout, "\"%s\",\"%s\",", "", "Min");

    for(ptr = global_item_list->head; ptr; ptr = ptr->next)
    {
	if(strcmp(ptr->grade_entered, "yes") == 0)
	{
	  if(save_opt == 1)
	     fprintf(stdout, "%s\t", ptr->min);
	  else
	     fprintf(stdout, "\"%s\",", ptr->min);
	}
	else
	{
	  if(save_opt == 1)
	     fprintf(stdout, "%s\t", "na");
	  else
	     fprintf(stdout, "\"%s\",", "na");
	}

    }

    if(min == -9999)
    {
      if(save_opt == 1)
	     fprintf(stdout, " \t \n");
      else
	     fprintf(stdout, "\" \",\" \"\n");
    }
    else
    { 
      if(save_opt == 1)
	     fprintf(stdout, "%4.2f\t%s\n", min, min_letter);
      else
	     fprintf(stdout, "\"%4.2f\",\"%s\"\n", min, min_letter);

    }
     
    if(save_opt == 1)
      fprintf(stdout, "%s\t%s\t", "", "Max");
    else
      fprintf(stdout, "\"%s\",\"%s\",", "", "Max");

    for(ptr = global_item_list->head; ptr; ptr = ptr->next)
    {
	if(strcmp(ptr->grade_entered, "yes") == 0)
	{
	  if(save_opt == 1)
	     fprintf(stdout, "%s\t", ptr->max);
	  else
	     fprintf(stdout, "\"%s\",", ptr->max);
	}
	else
	{
	  if(save_opt == 1)
	     fprintf(stdout, "%s\t", "na");
	  else
	     fprintf(stdout, "\"%s\",", "na");
	}

    }
    if(max == -9999)
    {
      if(save_opt == 1)
	     fprintf(stdout, " \t \n");
      else
	     fprintf(stdout, "\" \",\" \"\n");
    }
    else
    {
      if(save_opt == 1)
	     fprintf(stdout, "%4.2f\t%s\n", max, max_letter);
      else
	     fprintf(stdout, "\"%4.2f\",\"%s\"\n", max, max_letter);

    }

    if(save_opt == 1)
      fprintf(stdout, "%s\t%s\t", "", "Average");
    else
      fprintf(stdout, "\"%s\",\"%s\",", "", "Average");

    for(ptr = global_item_list->head; ptr; ptr = ptr->next)
    {
	if(strcmp(ptr->grade_entered, "yes") == 0)
	{
	  if(save_opt == 1)
	     fprintf(stdout, "%s\t", ptr->avg);
	  else
	     fprintf(stdout, "\"%s\",", ptr->avg);
	}
	else
	{
	  if(save_opt == 1)
	     fprintf(stdout, "%s\t", "na");
	  else
	     fprintf(stdout, "\"%s\",", "na");
	}

    }

    if(avg == -9999)
    {
      if(save_opt == 1)
	     fprintf(stdout, " \t \n");
      else
	     fprintf(stdout, "\" \",\" \"\n");
    }
    else
    {
    if(save_opt == 1)
	     fprintf(stdout, "%4.2f\t%s\n", avg, avg_letter);
    else
	     fprintf(stdout, "\"%4.2f\",\"%s\"\n", avg, avg_letter);
     
    }
}


void send_tab_csv_file(TOTAL_GRADE *std_grade, P_NODE *head, int save_opt)
{
    P_NODE *ptr;
    ITEM *item_ptr;
    GRADE *g_ptr;


    send_heading(save_opt);

    for(ptr = head; ptr; ptr = ptr->next)
    {
       if(ptr->data.group != FACULTY && *(ptr->data.realname) != '*')
       {
	if(save_opt == 1)
	   fprintf(stdout, "%s\t%s\t",ptr->data.id, ptr->data.realname);
        else
	   fprintf(stdout, "\"%s\",\"%s\",",ptr->data.id, ptr->data.realname);

        for(item_ptr = global_item_list->head; item_ptr; item_ptr = item_ptr->next)
	{
	    if(item_ptr->grades && item_ptr->grades->head)
	    {
		 for(g_ptr = item_ptr->grades->head; g_ptr; g_ptr = g_ptr->next)
		 {
		      if(strcmp(g_ptr->username, ptr->data.username) == 0)
		      {
		          if(strcmp(g_ptr->pending, "yes") == 0)
		          {
			      if(save_opt ==1)
				fprintf(stdout, "%s\t", "-");
			      else
				fprintf(stdout, "\"%s\",", "-");
		          }
		          else
		          {
			      if(strcmp(item_ptr->is_letter_grade, "yes") ==0)
			      {
			         if(save_opt ==1)
				   fprintf(stdout, "%s\t", g_ptr->letter);
			         else
				   fprintf(stdout, "\"%s\",", g_ptr->letter);
			      }
			      else
			      {
			        if(save_opt ==1)
				   fprintf(stdout, "%4.2f\t", g_ptr->score);
			        else
				   fprintf(stdout, "\"%4.2f\",", g_ptr->score);
			      }
                           
		          }
                     }
		 } 
	    }
	    else
	    {
                   if(save_opt == 1)
		   {
	              fprintf(stdout, "%s\t", "na");
		   }
		   else
		   {
	              fprintf(stdout, "\"%s\",", "na");
		   }

	    }
	}
	if(std_grade)
           print_total_grade_for_one_student(std_grade, ptr->data.username, save_opt);  
        else
	  {
	        if(save_opt == 1)
		{
	              fprintf(stdout, "%s\t", "na");
	              fprintf(stdout, "%s\n", "na");
		}
                else
		{
	              fprintf(stdout, "\"%s\",", "na");
	              fprintf(stdout, "\"%s\"\n", "na");
		}

	  }	  
       }
    }
    print_max_min_avg(std_grade, save_opt);


}

void    dump(TOTAL_GRADE *std_grade) 
{
    TOTAL_GRADE *ptr;
    send_content_type();
    for(ptr = std_grade; ptr; ptr = ptr->next)
    {
	 printf("%s ==  %4.2f  %s<br />", ptr->username, ptr->total, ptr->grade);
    }
   
}

void send_file(CONFIG_STRUCT *conf, int save_opt)
{
    P_NODE *head;
    TOTAL_GRADE *std_grade =0;

    head = build_option_person_list(conf);
    get_categories(conf, GRADE_BOOK_DB); /* shared_grade_book_db.c */
    
    if(!global_cat_list || !global_cat_list->head)
	cs_critical_error(ERR_GRADE_BOOK_NO_DATA_ITEM, "send file");
    get_items(conf, GRADE_BOOK_DB, 0);  /* shared_grade_book_db.c */
    if(!global_item_list || !global_item_list->head)
	cs_critical_error(ERR_GRADE_BOOK_NO_DATA_ITEM, "send file");
    get_all_grades(conf);
    get_items_min_avg_max(conf, GRADE_BOOK_DB); /* shared_grade_book_calculation_util.c */
    
    std_grade = calculate_total_grades(head, conf, GRADE_BOOK_DB); /* shared_grade_book_calculation_util.c */

    send_tab_csv_file(std_grade, head, save_opt);
    
    if(std_grade)
	   free_total_grade_list(std_grade);


    if(head)
        free_option_person_list(head);    /* shared_person_list.c */
    if(global_cat_list)
        free_category_list(global_cat_list);
    if(global_item_list)
        free_item_list(global_item_list);
    if(global_scale_list)
        free_scale_list(global_scale_list);

}


int
main ()
{
  char course[MAX_PATH +1];
  char key[MAX_KEY +1];
  char *next_url;
  int save_opt;

  SESSION user;
  CONFIG_STRUCT conf;
  
  cs_cgi_init();   /* shared_cs_util.h */
  read_parameters ( course, key, &save_opt);
  read_configuration_file (course, &conf);	
  validate_key (key, &user, &conf);	

  if(user.group != FACULTY)
       cs_critical_error(ERR_REQUEST_DENIED, "");

  next_url = hdf_get_value(global_cgi->hdf, "Query.nextUrl", "");
  if(save_opt == 0)
  {
    if(strlen(next_url) ==0)
       cs_critical_error(ERR_PARAM_MISSING, "grade_book_export_save");

    printf("Location: %s\n\n", next_url);
  }
  else 
  {
        send_file(&conf, save_opt);
  }
  cs_cgi_destroy();      

  return 0;			

}







