#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"

void
read_parameters ( char *course, char *key, int *item_id, int *number_letter_grades)
{
     char temp[MAX_KEY +1];

     cs_get_required_parameter("crs", course, MAX_PATH);
     cs_get_required_parameter("id", key, MAX_KEY);
     cs_get_required_parameter("item_id", temp, MAX_KEY);

     *item_id = atoi(temp);
     cs_get_optional_parameter("number_letter_grades", temp, MAX_KEY);
     if(strlen(temp))
	  *number_letter_grades = atoi(temp);

}



LETTER_GRADE_LIST *
get_all_letter_grades(int number)
{
#define MAX_TMP 40 
   int error =0;
   char name[MAX_TMP];
   LETTER_GRADE *ptr;
   LETTER_GRADE_LIST *list;
   int i;
   char *old_letter;
   char *old_points;
   int letter_id;
   char *letter;
   char *points =0;
   char *temp =0;
   int can_modify_letters = 0;

   

   list = (LETTER_GRADE_LIST *)malloc(sizeof(LETTER_GRADE_LIST));
   if(!list)
	cs_critical_error(ERR_MALLOC_FAILED, "grade_book_letter_grades get all letter grades");
   list->head =0;
   list->current =0;

   temp = hdf_get_value(global_cgi->hdf, "Query.can_modify_letters", "");
   if(strlen(temp))
	can_modify_letters = 1;


   for(i =0; i<=number; i++)
   {
       snprintf(name, MAX_TMP, "Query.letter_old_%d", i);
       old_letter = hdf_get_value(global_cgi->hdf, name, "");
       snprintf(name, MAX_TMP, "Query.points_old_%d", i);
       old_points = hdf_get_value(global_cgi->hdf, name, "");

       snprintf(name, MAX_TMP, "Query.letter_id_%d", i);
       temp = hdf_get_value(global_cgi->hdf, name, "");
       if(strlen(temp))
	    letter_id = atoi(temp);
       else
            letter_id = 0;

       snprintf(name, MAX_TMP, "Query.letter_%d", i);
       letter = hdf_get_value(global_cgi->hdf, name, "");

       snprintf(name, MAX_TMP, "Query.points_%d", i);
       points = hdf_get_value(global_cgi->hdf, name, "");


       if(letter_id > 0) 
       {
         if(can_modify_letters)
	 {
	    if(strcmp(letter, old_letter) || strcmp(points, old_points))
	    {
	      if(strlen(letter) && strlen(points))
	      {
                 if(check_spe_char(letter) && check_float_number(points))
	         {
                     ptr = (LETTER_GRADE*) malloc (sizeof(LETTER_GRADE));
		     ptr->next = 0;
		     ptr->letter_id = letter_id;
		     strncpy(ptr->letter, letter, MAX_GRADE_LEN +1); 
		     ptr->points = atof(points);
		     if(!list->head)
			  list->head = ptr;
		     else
			  list->current->next = ptr;
		     list->current = ptr;
	         }
                 else
	            error++;	  
	      }
              else
	      {
                     ptr = (LETTER_GRADE*) malloc (sizeof(LETTER_GRADE));
		     ptr->next = 0;
		     ptr->letter_id = letter_id;
		     ptr->points = -999999;               /* indicates delete this from db */
		     if(!list->head)
			  list->head = ptr;
		     else
			  list->current->next = ptr;
		     list->current = ptr;
	      }	      
	   }
	 }
	 else
	 {
	     if(strlen(points))
	     {
                 if(check_float_number(points))
		 {
                     ptr = (LETTER_GRADE*) malloc (sizeof(LETTER_GRADE));
		     ptr->next = 0;
		     ptr->letter_id = letter_id;
		     strncpy(ptr->letter, old_letter, MAX_GRADE_LEN +1); 
		     ptr->points = atof(points);
		     if(!list->head)
			  list->head = ptr;
		     else
			  list->current->next = ptr;
		     list->current = ptr;
		 }
		 else
		   error++;
	     }
	     else
		   error++;
	 }
       }
       else    /* new letter grades form */
       {
	      if(strlen(letter) && strlen(points))
	      {
                 if(check_spe_char(letter) && check_float_number(points))
	         {
                     ptr = (LETTER_GRADE*) malloc (sizeof(LETTER_GRADE));
		     ptr->next = 0;
		     ptr->letter_id = 0;
		     strncpy(ptr->letter, letter, MAX_GRADE_LEN +1); 
		     ptr->points = atof(points);
		     if(!list->head)
			  list->head = ptr;
		     else
			  list->current->next = ptr;
		     list->current = ptr;
	         }
                 else
	            error++;	  
	      }

       }
   }
   if(error >0)
        cs_critical_error(ERR_GRADE_BOOK_UPDATE_LETTER_GRADES, "grade_book_letter_grades");
     
   if(!list || !list->head)
        cs_critical_error(ERR_GRADE_BOOK_NO_CHANGE_LETTER_GRADES, "grade_book_letter_grades");

   return list;
    
#undef MAX_TMP  
}


void update_grade_letter(CONFIG_STRUCT *conf, int item_id, int number_letter_grades)
{
    LETTER_GRADE_LIST *list =0;
    LETTER_GRADE *ptr =0;
    char path[MAX_PATH +1];
    int ret = 0;
    sqlite3 *db;
     char *stmt;


    list = get_all_letter_grades(number_letter_grades);

    snprintf(path, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADE_BOOK_DB);
     ret = sqlite3_open(path, &db);
     if(ret)
      cs_critical_error(ERR_GRADES_DB, "save categories function");

     ret = sqlite3_exec(db, "Begin transaction update_insert_letterGrades", 0, 0, 0);

     if(ret)
     {
           sqlite3_close(db);
           cs_critical_error(ERR_GRADES_DB, "begin update insert letterGrades");
     }
     for(ptr=list->head; ptr; ptr = ptr->next)
     {
	if(ptr->points == -999999 && ptr->letter_id > 0)
	    stmt = sqlite3_mprintf("delete from LetterGrades where letterId=%d", ptr->letter_id);
	else if(ptr->letter_id > 0)
	    stmt = sqlite3_mprintf("update LetterGrades set letter='%q', points=%4.2f where letterId=%d", 
			    ptr->letter, ptr->points, ptr->letter_id);
	else
	    stmt = sqlite3_mprintf("insert into LetterGrades values(NULL,'%q', %4.2f, %d)",
			   ptr->letter, ptr->points, item_id); 
	
       if(stmt)
       {
           ret = sqlite3_exec(db, stmt, 0, 0, 0);
	   if(ret)
	   {
	        sqlite3_free(stmt);
                ret = sqlite3_exec(db, "rollback transaction update_insert_letterGrades", 0, 0, 0);
                ret = sqlite3_exec(db, "end transaction update_insert_letterGrades", 0, 0, 0);
		sqlite3_close(db);
		cs_critical_error(ERR_GRADES_DB, "transction update_insert_letterGrades failed");


	   }
           sqlite3_free(stmt);

       }

     }
     ret = sqlite3_exec(db, "commit transaction update_insert_letterGrades", 0, 0, 0);
     ret = sqlite3_exec(db, "end transaction update_insert_letterGrades", 0, 0, 0);
     sqlite3_close(db);
     free_letter_grade_list(list);

  

		    
}

    
void do_action(CONFIG_STRUCT *conf, const char *course, const char *key, int item_id, int number_letter_grades)
{
   if(number_letter_grades)
   {
     update_grade_letter(conf, item_id, number_letter_grades);
     printf("Location: %s?crs=%s&id=%s&item_id=%d\n\n", "grade_book_letter_grades", course, key, item_id);
   }
   else
   {

      get_one_item(conf, item_id, GRADE_BOOK_DB);         /* shared_grade_book_db.h */
      get_letter_grades(conf, item_id, GRADE_BOOK_DB);     /* shared_grade_book_db.h */
      
          
      if(!global_item_list)
	 cs_critical_error(ERR_GRADES_DB, "grade_book_letter_grades no list");
      if(!global_item_list->head) 
	 cs_critical_error(ERR_GRADES_DB, "grade_book_letter_grades");

      if(strcmp(global_item_list->head->grade_entered, "no") == 0)
	 cs_set_int_value("can_modify_letters", 1);
    
      cs_set_int_value("item_id", item_id);
      cs_set_int_value("display_letter_grades", 1);
      cs_set_int_value("max_letter_len", MAX_GRADE_LEN);
      cs_set_int_value("max_point_len", MAX_POINT_LEN);
      set_letter_grades_value();
      free_item_list(global_item_list);
      free_letter_grade_list(global_letter_grades);
      cs_load_lang("grade_book_items");
      cs_cgi_display ("grade_book_letter_grades", 0);
 }



}


int
main ()
{
  char course[MAX_PATH +1];
  char key[MAX_KEY +1];
  SESSION user;
  CONFIG_STRUCT conf;
  int item_id;
  int number_letter_grades =0; 
  
  cs_cgi_init();   /* shared_cs_util.h */
  read_parameters ( course, key, &item_id, &number_letter_grades);
  read_configuration_file (course, &conf);	
  validate_key (key, &user, &conf);	
  if(user.group != FACULTY)
     cs_critical_error(ERR_REQUEST_DENIED, "grade_book_items");

  cs_set_course_info(&conf);  
  set_grade_book_menu("grade_book_items", key, course); /* shared_grade_book_menu.h */
  cs_load_lang("grade_book_menu_util");

  do_action(&conf, course, key, item_id, number_letter_grades);

  cs_cgi_destroy();      

  return 0;			

}




