#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

#include "../global.h"


#include <ClearSilver.h>
#include "shared_cs_util.h"
#include "shared_time.h"
#include "shared_strtrm.h"
#include "shared_server_string.h"
#include "shared_system_data.h"


CGI *global_cgi = 0;
int global_theme =0;
double global_program_start_time = 0;         	/* used to record the exact time a Manhattan program was started,
                                   		** so we can measure its run time
                                   		*/

static double
accurate_timeofday()
{
  struct timeval tv;
  double mytime = 0;
  
  if(!gettimeofday(&tv, NULL))
     mytime = tv.tv_sec + (tv.tv_usec / 1000000.0);
  
  return mytime;
}     



void
cs_cgi_destroy()
{
  free_system_data();
  cgi_destroy(&global_cgi);

}



/* We want uploaded files to go to Manhattan's tmp directory.
** To do that, we need to set Config.Upload.TmpDir in the hdf
** dataset.  Unfortunately our TMP_PATH, #defined in global.h
** has a trailing '/' that ClearSilver doesn't need, which makes
** this harder than it should be.
*/
static void set_upload_tmp_dir()
{
 char *str;
 char *ptr;

 str = (char *) malloc((strlen(TMP_PATH) + 1) * sizeof(char));
 strcpy(str, TMP_PATH);
 ptr = strrchr(str,'/');
 if(ptr && (*(ptr + 1) == '\0'))
   *ptr = '\0';
   
 cs_set_value("Config.Upload.TmpDir", str); 
 
 free(str);

}


 
void basic_init()
{
 HDF *hdf;
 umask(0006);
 hdf_init(&hdf);
 cgi_init(&global_cgi,hdf);
 cgi_parse (global_cgi);      
 cs_set_loadpath(); 

 get_default_conf();    /* shared_system_data.c */
 
}
 

void 
cs_cgi_init()
{
 HDF *hdf;
 
 if(system_data_int("RECORD_RUN_TIME"))   /* shared_system_data.h */
    global_program_start_time = accurate_timeofday();
 
 umask(0006);
 
 hdf_init(&hdf);

 if(!global_cgi)
 {
   if( cgi_init(&global_cgi,hdf) != STATUS_OK )
	cs_critical_error(ERR_GENERAL_ERROR, "cgi init failed"); 
   
 }
 set_upload_tmp_dir();
 
 
 cgi_parse (global_cgi);                    /** Adds POST data to the HDF structure. **/ 

   
/** uncomment the next line to automatically have ClearSilver send all html as
*** the specified charset
**/ 
// hdf_set_value(global_cgi->hdf, "cgiout.ContentType", "text/html; charset=UTF-8\n\n");
 
 global_theme = system_data_int("DEFAULT_THEME");      /* shared_system_data.h */
 cs_set_loadpath();

}



static void
cs_print_error()  
{
 char cs_path[MAX_PATH + 1];
 

 cs_set_image_path();
 
 snprintf(cs_path,MAX_PATH + 1, "%s/%s%d/critical_error.cs", 
                       IMAGES_DIR, THEME_DIR_PREFIX, global_theme);
 cgi_display(global_cgi,cs_path);
 
}     



static 
void cs_set_error_msg( char *error_code)
{
#define MAX_STR 80

  char lang_path[MAX_PATH + 1];
  char node_name[MAX_STR + 1];
  char default_error[MAX_STR + 1];
  HDF *hdf;
  int success = 0;  

   snprintf(default_error, MAX_STR + 1, "Error code: %s", error_code);
   if(hdf_init (&hdf) == STATUS_OK)
    {
      snprintf(lang_path, MAX_PATH + 1, "%s/%s%d/lang/error.lang", 
                              IMAGES_DIR, THEME_DIR_PREFIX, global_theme);

      if(hdf_read_file(hdf, lang_path) == STATUS_OK)
       {
        snprintf(node_name, MAX_STR + 1, "lang.error.%s", error_code);
        if(hdf_set_value(global_cgi->hdf, "error_msg", hdf_get_value (hdf, node_name, default_error)) == STATUS_OK)
           success = 1;
       }
      hdf_destroy(&hdf);
    }  
  
   if(!success)
      hdf_set_value(global_cgi->hdf, "error_msg", default_error);

#undef MAX_STR
}




void
cs_critical_error( const char *error_code, const char *detail)
{
#define MAX_HDF_ELEMENT 50

 char *my_detail;
 int len;
 char *my_code;

   len = strlen(error_code);
   if(len)
   {
     my_code = (char *) malloc( len + 1);
     strncpy(my_code, error_code, len + 1);
     hdf_set_value(global_cgi->hdf, "error_code", my_code);
     cs_set_error_msg(my_code);
     free(my_code);
   } 
   len = strlen(detail);
   if(len)
    {  
      /* because we need to preserve 'const' msg */
      my_detail = (char *) malloc( len + 1);
      strncpy(my_detail, detail, len + 1);
      hdf_set_value(global_cgi->hdf, "error_detail", my_detail);
      free(my_detail);
    }  

     
    cs_print_error();
    cs_cgi_destroy();
    exit(0);

   
#undef MAX_HDF_ELEMENT 
}


void
cs_timeout_error(char *error_code,  char *detail)
{
#define MAX_HDF_ELEMENT 50
   int len;

   cs_set_value("login_url", system_data_str("EXIT_URL"));
   len = strlen(error_code);
   if(len)
      cs_set_value("error_code", error_code);

   len = strlen(detail);
   if(len)
      cs_set_value("error_detail", detail);

    cs_set_image_path();
    cs_load_lang("error");
    cs_cgi_display("critical_error", 0);
    cs_cgi_destroy();
    exit(0);
}


void 
cs_dump_hdf()
{
 printf("Content-type: text/html\n\n");
 printf("<html>\n<body>\n<pre>\n");
 hdf_dump(global_cgi->hdf,"");
 printf("</pre>\n</html>");
      
}




NEOERR *
cs_load_lang(const char *cs_file)
{
 char lang_path[MAX_PATH + 1];
 static unsigned char count = 0;
 char name[30];
 
 snprintf(lang_path, MAX_PATH + 1, "%s/%s%d/%s/%s%s", 
                             IMAGES_DIR, THEME_DIR_PREFIX, global_theme, LANG_DIR, cs_file,LANG_EXTENSION);
               
 snprintf(name, 30, "about.lang_file.%d", count);
 cs_set_value(name, lang_path);
 count++;           
  
 return hdf_read_file(global_cgi->hdf, lang_path);
}



static
void cs_set_run_time()
{
 double now;
 char timestring[50];
 
 if(global_program_start_time)   /* will be zero if it was never set by a call to cs_cgi_init() */
  { 
   now = accurate_timeofday();
   snprintf(timestring, sizeof(timestring),"%5.3f",now - global_program_start_time);
   cs_set_value("runtime", timestring);
  } 
}








void
cs_cgi_display(const char *cs_file, int load_lang)
{
 char cs_path[MAX_PATH + 1];
 NEOERR *err;
 
   

  if(load_lang)
    cs_load_lang(cs_file);


 if(system_data_int("RECORD_RUN_TIME")) /* shared_system_data.c */
    cs_set_run_time();
   
    cs_set_image_path();
 
    snprintf(cs_path, MAX_PATH + 1, "%s/%s%d/%s%s", 
                    IMAGES_DIR, THEME_DIR_PREFIX, global_theme, cs_file, CLEARSILVER_EXTENSION);

    cs_set_value("about.cs_file", cs_path);
    
    /* VERSION is #defined in global.h */
    cs_set_value("about.version", VERSION);
     
    err = cgi_display(global_cgi,cs_path);
    if(err != STATUS_OK)
    {
	  cgi_neo_error(global_cgi, err);
    }
} 
 


void
cs_set_current_time()
{
   char *current_time = 0;

   current_time = get_time_string();   /* shared_time.c */

   hdf_set_value(global_cgi->hdf, "current_time", current_time);

   if(current_time)
      free(current_time);
}



void
cs_set_image_path()
{
 char path[MAX_PATH + 1];
 

 snprintf(path,MAX_PATH + 1, "%s%s%d/", system_data_str("IMAGE_PATH"), THEME_DIR_PREFIX, global_theme);        
 hdf_set_value (global_cgi->hdf,"image_path", path);  
 
}     



/** When you use Clearsilver's 'include' command in a template file to 
*** include (and parse) another clearsilver file, the parser searches the
*** hdf.loadpaths.x list to find the file.
***
*** A call to this function should be sufficient to use
***
***   <?cs include:"somefile.cs" ?> 
***
*** within a Manhattan theme_x directory.
**/
void
cs_set_loadpath()
{

char path[MAX_PATH + 1];

 snprintf(path,MAX_PATH + 1, "%s/%s%d", IMAGES_DIR, THEME_DIR_PREFIX, global_theme);      
 hdf_set_value(global_cgi->hdf, "hdf.loadpaths.0", path);
}



void
cs_set_course_info(CONFIG_STRUCT *conf)
{

   global_theme = conf->theme;
   cs_set_image_path();

   hdf_set_value(global_cgi->hdf, "course_no", conf->course_no);
   hdf_set_value(global_cgi->hdf, "semester", conf->semester);
   hdf_set_value(global_cgi->hdf, "course_title", conf->title);
   hdf_set_value(global_cgi->hdf, "instructor", conf->instructor);
   hdf_set_int_value(global_cgi->hdf, "is_template", conf->template);

}








void
cs_set_back_url(const char *course, const char *key, const char *program)
{
    char url[MAX_PATH +1];

    snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", program, course, key);
    hdf_set_value(global_cgi->hdf, "back_url", url);
}



char *
cs_get_string_value (char *name, char *value, int maxlen)
{
#define MAX_HDF_NAME 50

 char hdf_name[MAX_HDF_NAME + 1];
 char *tmp_value = 0;
 
 
 snprintf(hdf_name, MAX_HDF_NAME + 1, "Query.%s", name);
 hdf_get_copy(global_cgi->hdf, hdf_name, &tmp_value, "");
 
  
 if(!tmp_value)
    return ERR_PARAM_MISSING;
    
 strtrm(tmp_value);   /* shared_strtrm.c */   
 if(!*tmp_value)
   {
     free(tmp_value);
     return ERR_PARAM_MISSING;
   }
  else
   if(strlen(tmp_value) > maxlen)
    {
     free(tmp_value);
     return ERR_PARAM_LONG;
    } 
      
   snprintf(value, maxlen + 1, "%s", tmp_value);   
   free(tmp_value);

   return ERR_NONE;
              
              
#undef MAX_HDF_NAME
}



void
cs_get_optional_parameter (char *name, char *value, int maxlen)
{
#define MAX_HDF_NAME 50

 char hdf_name[MAX_HDF_NAME + 1];
 char *tmp_value = 0;
 
 
 *value = '\0';
 snprintf(hdf_name, MAX_HDF_NAME + 1, "Query.%s", name);
 hdf_get_copy(global_cgi->hdf, hdf_name, &tmp_value, "");
 
  
 if(!tmp_value)
     return;
     
 strtrm(tmp_value);   /* shared_strtrm.c */    
 if(!*tmp_value)
   {
     free(tmp_value);
     return;
   }
  else
   if(strlen(tmp_value) > maxlen)
    {
     free(tmp_value);
     cs_critical_error(ERR_PARAM_LONG, name);
    } 
      
   snprintf(value, maxlen + 1, "%s", tmp_value);   
   free(tmp_value);
              
              
#undef MAX_HDF_NAME
}


void
cs_get_required_parameter (char *name, char *value, int maxlen)
{
#define MAX_HDF_NAME 50

 char hdf_name[MAX_HDF_NAME + 1];
 char *tmp_value = 0;
 
 
 snprintf(hdf_name, MAX_HDF_NAME + 1, "Query.%s", name);
 hdf_get_copy(global_cgi->hdf, hdf_name, &tmp_value, "");
 
  
 if(!tmp_value)
    cs_critical_error(ERR_PARAM_MISSING, name);
    
 strtrm(tmp_value);   /*shared_strtrm.c */   
 if(!*tmp_value)
   {
     free(tmp_value);
     cs_critical_error(ERR_PARAM_MISSING, name);
   }
  else
   if(strlen(tmp_value) > maxlen)
    {
     free(tmp_value);
     cs_critical_error(ERR_PARAM_LONG, name);
    } 
      
   snprintf(value, maxlen + 1, "%s", tmp_value);
   free(tmp_value);
              
              
#undef MAX_HDF_NAME
}


void
cs_set_server_name()
{
    char server_string[MAX_PATH +1];

    get_server_string(server_string, MAX_PATH +1);   /* shared_server_string.h */
    cs_set_value("server_name", server_string);
}



void
cs_set_bin_alias()
{
   cs_set_value("bin_alias", system_data_str("ALIAS")); 
}



char *
cs_survey_get_stringvalue(const char *name)
{
#define MAX_HDF_NAME 50

 char hdf_name[MAX_HDF_NAME + 1];
 char *tmp_value = 0;
 
 
 snprintf(hdf_name, MAX_HDF_NAME + 1, "Query.%s", name);
 hdf_get_copy(global_cgi->hdf, hdf_name, &tmp_value, "");
 
  
 if(!tmp_value)
    cs_critical_error(ERR_PARAM_MISSING, name);
    
 strtrm(tmp_value);   /* shared_strtrm.c */   
 if(!*tmp_value)
   {
     free(tmp_value);
     cs_critical_error(ERR_PARAM_MISSING, name);
   }
      
  return tmp_value; 
#undef MAX_HDF_NAME
}



char *
cs_survey_get_optvalue(const char *name)
{
#define MAX_HDF_NAME 50

 char hdf_name[MAX_HDF_NAME + 1];
 char *tmp_value = 0;
 
 snprintf(hdf_name, MAX_HDF_NAME + 1, "Query.%s", name);
 hdf_get_copy(global_cgi->hdf, hdf_name, &tmp_value, "");
    
 strtrm(tmp_value);   /*shared_strtrm.c */   
 if(!*tmp_value)
    return 0;
 else
   return tmp_value;

#undef MAX_HDF_NAME 
} 
      



void
cs_set_theme_path()
{
    char cwd[MAX_PATH +1];
    char path[MAX_PATH +1];
    char *ptr;

    if(getcwd(cwd, MAX_PATH +1))
    {
       ptr = strrchr(cwd, '/');
       if(ptr)
	   *ptr = '\0';
       snprintf(path, MAX_PATH +1, "%s/%s/%s%d", cwd, "images",THEME_DIR_PREFIX, global_theme); 
       cs_set_value("theme_path", path);
    }
    else
       cs_critical_error(ERR_NO_THEME_PATH, "");
}




/** returns html-escaped source_string in newly allocated
 *** new_string.  Caller is responsible for freeing new_string
 ***/

void
cs_html_escape_string(char *source_string, char **new_string)
{
    *new_string = 0;
    if(cgi_html_escape_strfunc(source_string,new_string) != STATUS_OK)
    {
            if(*new_string)
            {
               free(*new_string);
            }
        *new_string = (char *) malloc( (strlen(source_string) + 1) * sizeof(char));
        if(*new_string)
            strcpy(*new_string, source_string);
    }

}



/* sets text strings used in central login logs */
int cs_set_event_msg()
{
  char lang_path[MAX_PATH + 1];

  snprintf(lang_path, MAX_PATH + 1, "%s/%s%d/lang/log_event.lang", IMAGES_DIR, THEME_DIR_PREFIX, global_theme);
  return (hdf_read_file(global_cgi->hdf, lang_path) == STATUS_OK)? 1: 0;

}





/* caller must free hdf */ 
void
get_lang_string(HDF **hdf)
{
  char lang_path[MAX_PATH +1];

  if(hdf_init (hdf) == STATUS_OK)
   {
      snprintf(lang_path, MAX_PATH + 1, "%s/%s%d/lang/lang.lang", IMAGES_DIR, THEME_DIR_PREFIX, global_theme);
      hdf_read_file(*hdf, lang_path);
   }

}


