#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_file_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_grade_book_util.h"
#include "manhat-lib/shared_grade_book_menu.h"

void
read_parameters ( char *course, char *key, int *save_option)
{
    char save[20];

    cs_get_required_parameter("crs", course, MAX_PATH);
    cs_get_required_parameter("id", key, MAX_KEY);
    cs_get_required_parameter("save_option", save, 19);
    if(strcmp(save, "yes") ==0)
	   *save_option = 1;
    else if(strcmp(save, "no") == 0)
	  *save_option = 0;
    else if(strcmp(save, "default") == 0)
	  *save_option = 2;
    else if(strcmp(save, "mysetting") == 0)
	  *save_option = 3;

}

void get_cal_methods(SCORING_METHOD *my_scoring_method, ROUNDING_METHOD * my_rounding_method)
{
    char temp[20];
    int num;

    cs_get_required_parameter("scoring_method", temp, 19);
    num = atoi(temp);
    if(num == 0)
      *my_scoring_method = NO_CAL;
    else if(num == 1)
      *my_scoring_method = BASIC_POINTS;
    else if(num == 2)
      *my_scoring_method = CATEGORY_WEIGHT;
    else
      cs_critical_error(ERR_INVALID_CAL_METHOD, "grade_book_final_save get_cal_methods");

    cs_get_required_parameter("rounding_method", temp, 19);
    num = atoi(temp);
    if(num == 0)
	*my_rounding_method = WHOLE_NUMBER;
    else if(num == 1)
	*my_rounding_method = NEAREST_TENTH;
    else
      cs_critical_error(ERR_INVALID_CAL_METHOD, "grade_book_final_save get_cal_methods");
    
}

void init_grade_conf(GRADE_BOOK_CONFIGURE *conf)
{
      conf->scoring_method = 0;
      conf->rounding_method = 0;
      conf->feature1 = 0;
      conf->feature2 = 0;
      conf->feature3 = 0;
      conf->feature4 = 0;
      conf->feature5 = 0;
      conf->feature6 = 0;
}

void save_calculation_method(CONFIG_STRUCT *conf)
{
  char path[MAX_PATH +1];
  GRADE_BOOK_CONFIGURE grade_conf;
  FILE *fp;

  get_cal_methods(&(grade_conf.scoring_method), &(grade_conf.rounding_method));
  
  snprintf(path, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADE_CAL_CONF_FNAME);
  fp = fopen(path, "w");
  if(!fp)
      cs_critical_error(ERR_FOPEN_WRITE_FAILED, "grade_book_final_save save calculation method"); 
  if(fwrite(&grade_conf, sizeof(GRADE_BOOK_CONFIGURE), 1, fp) != 1)
      cs_critical_error(ERR_FWRITE_FAILED, "grade_book_final_save save calculation method");
   fclose(fp);
	 
}

void
set_red_star( int number)
{
    char name[MAX_PATH +1];
    snprintf(name, MAX_PATH +1, "scale.%d.is_red", number);
    cs_set_int_value(name, 1);

}


int get_one_scale(int number, double *start, char *grade, double pre)
{
  #define MAX_TEMP_LEN 35
  char name[MAX_TEMP_LEN];
  char *start_ptr =0, *grade_ptr =0;

  snprintf(name, MAX_TEMP_LEN, "Query.scale_%d", number);
  start_ptr = hdf_get_value(global_cgi->hdf, name, "");
  snprintf(name, MAX_TEMP_LEN, "Query.grade_%d", number);
  grade_ptr = hdf_get_value(global_cgi->hdf, name, "");
  
  snprintf(name, MAX_TEMP_LEN, "scale.%d.start", number);
  cs_set_value(name, start_ptr);
  snprintf(name, MAX_TEMP_LEN, "scale.%d.grade", number);
  cs_set_value(name, grade_ptr);
  
  if(strlen(start_ptr)== 0 || strlen(grade_ptr)==0)
      return -1;      // not be used
  if( !check_float_number(start_ptr))
  {
        set_red_star(number);
	return 0;
  }
  if(pre < atof(start_ptr))
  {
        set_red_star(number);
	return 0;
  }
  strncpy(grade, grade_ptr, MAX_GRADE_LEN +1);
  *start = atof(start_ptr);

  return 1;
  #undef MAX_TEMP_LEN 
}

SCALE_LIST *
check_all_scales(int *error)
{
   int number, i, flag =0;
   SCALE *ptr;
   SCALE_LIST *scale_list;
   double pre = 50000, start =0;
   char grade[MAX_GRADE_LEN +1];

   number = hdf_get_int_value(global_cgi->hdf, "Query.number_scales", 0);
   if(!number)
      cs_critical_error(ERR_PARAM_MISSING, "check_all_scales");

   scale_list = (SCALE_LIST *)malloc(sizeof(SCALE_LIST));
   scale_list->head =0;
   scale_list->current =0;
   
   for(i = 0; i<number; i++)
   {
	flag = get_one_scale(i, &start, grade, pre);
	if(flag == 1)
        {
               ptr = (SCALE*)malloc(sizeof(SCALE));
               ptr->start = start;
               strncpy(ptr->grade, grade, MAX_GRADE_LEN +1);
               ptr->end = pre;
               ptr->next =0;
               if(!scale_list->head)
	             scale_list->head = ptr;
                else
	            scale_list->current->next = ptr;
                scale_list->current = ptr;
                pre = ptr->start;
      }
      else if (flag ==0)
           (*error)++;

   }
   return scale_list;
      
}

void test_config_file(CONFIG_STRUCT *conf)
{
  char path[MAX_PATH +1];

  snprintf(path, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADE_CAL_CONF_FNAME);
  if(!file_exists(path))
     cs_set_int_value("final", 0);

}

int save_scales(SCALE_LIST *scale_list, CONFIG_STRUCT *conf)
{ 
     int ret = 0;
     sqlite3 *db;
     char *stmt;
     char name[MAX_PATH +1];


     snprintf(name, MAX_PATH +1, "%s%s/%s", conf->course_path, GRADE_BOOK_DIR, GRADE_BOOK_DB);
     ret = sqlite3_open(name, &db);    
     if(ret)       
	 return 0; 
     ret = sqlite3_exec(db, "delete from Scales where grade != 'XXXXX'",  0,0,0);    
     if(ret)    
     {       
	 sqlite3_close(db);            
	 return 0;    
     }
    for(scale_list->current = scale_list->head; scale_list->current; scale_list->current = scale_list->current->next)
    {
	 stmt = sqlite3_mprintf("insert into Scales values(NULL, '%q', %4.2f, %4.2f)", 
			 scale_list->current->grade, scale_list->current->start, scale_list->current->end);
	 if(stmt)
	 {
              ret = sqlite3_exec(db, stmt, 0,0,0);
	      if(ret)
	      {
		 sqlite3_free(stmt);
		 sqlite3_close(db);
		 return 0;
	      }
	     sqlite3_free(stmt);
	 }
    } 
    sqlite3_close(db);
    return 1;
}


int
main ()
{
  char course[MAX_PATH +1];
  char key[MAX_KEY +1];
  char *next_url;
  int save_option, error =0;
  SCALE_LIST *scale_list =0;

  SESSION user;
  CONFIG_STRUCT conf;
  
  cs_cgi_init();
  read_parameters (course, key, &save_option);
  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(strlen(next_url) == 0)
     cs_critical_error(ERR_PARAM_MISSING, "grade_book_final_save, main function");
  
  if(save_option == 0 || save_option == 3)          /* do not save changes */
    printf("Location: %s\n\n", next_url); 
  else if(save_option == 2)    /* get default scales */
    printf("Location: %s&default=yes\n\n", next_url); 
  else if(save_option == 1)    /* save changes */
  {	  
    
    scale_list = check_all_scales(&error);
    if(error)
     {
	set_grade_book_menu("grade_book_final", key, course); /* shared_grade_book_menu.h */
	cs_load_lang("grade_book_menu_util");
        test_config_file(&conf);
        cs_set_course_info(&conf);
	free_scale_list(scale_list);
        cs_cgi_display ("grade_book_final", 1);
     }
    else
     {
       if(save_scales(scale_list, &conf))
          save_calculation_method(&conf );
        else
          cs_critical_error(ERR_GRADES_DB, "grade_book_final_save");
       
	free_scale_list(scale_list);
        printf("Location: %s\n\n", next_url); 
     }
  }   
  cs_cgi_destroy();  
  return 0;			

}

