#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
       
#include "ClearSilver.h"

#include "global.h"
#include "custom.h"
#include "survey.h"

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_file_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_time.h"
#include "manhat-lib/shared_copy_file.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_add_util.h"



/** DEFAULT_SUBJECT will be used as the subject of the message
*** sent, IF ONE IS NOT PROVIDED on the command line via subject=.   
*** Whether taken from the following #define, or from the command line, 
*** the subject will be truncated to MAX_SUBJECT (i.e. 45) characters
**/

#define DEFAULT_SUBJECT  "Course Evaluation"


/** DEFAULT_MSG will be used as the body of the message
*** sent, IF ONE IS NOT PROVIDED on the command line via msg=   
*** Whether from the following #define, or from the command line, 
*** DO NOT MAKE ANY LINE (much) LONGER THAN 70 characters.  (End a line with
*** a '\n\' ).  Lines much longer than 70 characters will look UGLY when the message
*** is read.  Lines longer than 255 characters might cause the program to fail.
**/


#define DEFAULT_MSG      "Please take the attached course evaluation survey.  Your responses\n"\
                         "are completely anonymous.\n\n"\
                         "(This survey was posted on behalf of your instructor by an automated\n"\
                         "process.)"



/** These correspond to choices the teacher gets to make
*** when delivering the survey.  Probably should leave them
*** alone.
**/
#define ALLOW_STUDENTS_TO_VIEW_RESULTS 0
#define ALLOW_STUDENTS_TO_VIEW_SURVEY_AGAIN 0
#define STUDENT_ANSWER_REQUIRED 0


typedef struct sched_dates
{
   time_t start_time;
   time_t end_time;
   int    no_ending;
} SCHED_DATES;






static
void read_parameters (char *course,               /* the course to receive the survey */
	              time_t *result_time,        /* when should teacher be able to see survey results? */
		      SCHED_DATES *sched_date,    /* message will be displayed btwn start_date and end_date */
		      char *username,             /* username of *TEACHER* who will be sending the survey */
		      char *survey_id,            /* the internal ID of the survey */
                      char *msg_subject,          /* the subject of the message (optional)*/
                      char **msg_body)             /* the body of the message (optional) */
{                   
   char temp[80];
   char *msg;
   

   cs_get_required_parameter ("crs", course, MAX_PATH);   /* shared_cs_util.c */
   cs_get_required_parameter ("survey_id", survey_id, MAX_PATH);
   cs_get_required_parameter ("username", username, MAX_USERNAME);


   cs_get_required_parameter ("result_time", temp, 79);
   *result_time = atol(temp);

   cs_get_required_parameter ("start_time", temp, 79);
   sched_date->start_time = atol(temp);

   cs_get_required_parameter ("end_time", temp, 79);
   sched_date->end_time = atol(temp);
   sched_date->no_ending = 0;

  
   /** the subject of the message is either from the command line
   *** or is DEFAULT_SUBJECT
   **/
   cs_get_optional_parameter ("subject", temp, MAX_SUBJECT);  /* shared_cs_util.c */
   if(*temp)
      strncpy(msg_subject, temp, MAX_SUBJECT + 1);
   else
      strncpy(msg_subject, DEFAULT_SUBJECT, MAX_SUBJECT + 1);
   *(msg_subject + MAX_SUBJECT) = '\0';   
   
    
    
   /** the body of the message is either from the command line
   *** or is DEFAULT_MSG
   **/
    msg = hdf_get_value (global_cgi->hdf, "Query.msg", "");   /* from ClearSilver library */
    if(!msg || !(*msg))
      {
       *msg_body = (char *) malloc((strlen(DEFAULT_MSG) + 1) * sizeof(char));
       strncpy(*msg_body, DEFAULT_MSG, strlen(DEFAULT_MSG) + 1);
      }
    else
      {
       *msg_body = (char *) malloc((strlen(msg) + 1) * sizeof(char));
       strncpy(*msg_body, msg, strlen(msg) + 1);
      } 
       

   if(sched_date->start_time >= sched_date->end_time)
	cs_critical_error (ERR_END_BEFORE_START, "");

}







static void
write_msg_file (const char *msg, const char *unique_fname)
{
  FILE  *outfp;
  char filepath[MAX_PATH + 1];

  snprintf (filepath, MAX_PATH + 1, "%s/%s", discussion_path, unique_fname);
  
  outfp = fopen (filepath, "w");
  if (!outfp)
    cs_critical_error (ERR_FOPEN_WRITE_FAILED, filepath);

  fprintf (outfp, "%s", msg);
  fclose (outfp);
}












/* note that this creates the file */
static void
get_unique_fname(char *unique_fname, const char *base_dir, const char *filetype, time_t *time_sent)
{
 int fd;
 
 fd = get_unique_fd(base_dir, filetype, unique_fname, time_sent);  /* shared_news_util.c */
 close(fd);
} 







static void
process_message_file (const char *msg,  char *msg_fname, time_t *time_sent)
{
    get_unique_fname (msg_fname, discussion_path, "msg", time_sent);
    write_msg_file (msg, msg_fname);
}








static void
complete_send (const char *msg_fname, P_NODE *user, time_t time_sent,  const char *subject,
	       const char *survey_dir, SCHED_DATES *mydate)
{
  FILE  *inbox_fp;
  int info_fd, inbox_fd;
  struct stat buf;
  NEWS_PERSON person;
  
  char info_fname[MAX_FILENAME + 1];
  char inbox_fname[MAX_PATH + 1];
  int msg_id;
  CENTRAL_INBOX_RECORD inbox_record, new_inbox_record;
  int inbox_record_size,  attachment_size;
  
  ATTACHMENT attach;
  
 /* memorize the sizes of these data structures, 
 ** so we don't have to repeatedly call sizeof()
 */
  inbox_record_size = sizeof(CENTRAL_INBOX_RECORD); 
  attachment_size = sizeof(ATTACHMENT);
  
 /* this user has already read this message
 ** set a NEWS_PERSON record to be written
 ** to the end of the new inf file.
 */
 strncpy(person.username,user->data.username, MAX_USERNAME + 1);
 strncpy(person.realname, user->data.realname, MAX_NAME + 1);
 person.time_read = time_sent;
 person.user_unlocked = 0;


  /* set up as much of the new inbox record as we can before locking
  ** the inbox.dat file
  */  
  strncpy(new_inbox_record.info.msg_fname, msg_fname, MAX_FILENAME + 1);
  strncpy(new_inbox_record.info.sender, user->data.username, MAX_USERNAME + 1);
  
  strncpy(new_inbox_record.info.sender_realname, user->data.realname, MAX_NAME + 1);

  *(new_inbox_record.info.sender_realname + MAX_NAME) = '\0';
  
    
  strncpy(new_inbox_record.info.receiver_username,"",MAX_USERNAME + 1);  
  strncpy(new_inbox_record.info.subject, subject, MAX_SUBJECT + 1);
  new_inbox_record.info.time_sent = time_sent;
  new_inbox_record.info.attachments = -1;      /* pretend it's a web site attached */
  new_inbox_record.info.sender_team = user->data.team;
  new_inbox_record.info.reply_to = -1;
  
  /* get the name of the 'inf' file to do so, we need to open
  ** (create) the file
  */
  info_fd = get_unique_fd (discussion_path,"inf", info_fname, &time_sent);
  /* don't bother to lock it, since no one knows it's there yet! */
  
  strncpy(new_inbox_record.info_fname,info_fname,MAX_FILENAME + 1);

  SET_BASIC_STATUS(new_inbox_record.status, TIMED_RELEASE);   /* SET_BASIC_STATUS #defined in global.h */

  new_inbox_record.release_time = mydate->start_time;      
  new_inbox_record.unrelease_time = mydate->end_time;
  
  /* now open and lock the inbox.dat file */
  snprintf(inbox_fname,MAX_PATH + 1,"%s%s",central_discussion_path,INBOX_FNAME);
  inbox_fp = fopen(inbox_fname,"a+");
  if(!inbox_fp)                              /* couldn't open or create inbox.dat */
    cs_critical_error(ERR_FOPEN_WRITE_FAILED,inbox_fname);
  inbox_fd = fileno(inbox_fp);
  get_exclusive_lock(inbox_fd, 1);                      /* shared_lock.c */
  
  
  /* get the next available msg_id, by incrementing the msg_id of the
  ** last msg in the inbox.dat file
  */
  fstat(inbox_fd, &buf);
  if(!buf.st_size)    /* this is the first message */
     msg_id = 1;
  else
    {
     if(fseek(inbox_fp,-inbox_record_size,SEEK_END) == -1)
       cs_critical_error(ERR_FSEEK_FAILED, inbox_fname);
     if(fread( &inbox_record, inbox_record_size, 1, inbox_fp) != 1)
       cs_critical_error(ERR_FREAD_FAILED, inbox_fname);
     msg_id =  inbox_record.info.msg_id + 1;
    }
    
   new_inbox_record.info.msg_id = msg_id;
   new_inbox_record.info.topic_id =  msg_id;
   if(fseek(inbox_fp,0,SEEK_END) == -1)
     cs_critical_error(ERR_FSEEK_FAILED, inbox_fname);
   if(fwrite(&new_inbox_record, inbox_record_size,1,inbox_fp) != 1)
      cs_critical_error(ERR_FWRITE_FAILED, inbox_fname);



  /* now write the info file */   
  if (write (info_fd, &new_inbox_record.info, sizeof (NEWS_INFO)) != sizeof(NEWS_INFO))
    cs_critical_error (ERR_FWRITE_FAILED, "on info file");

  strncpy (attach.unique_fname, survey_dir, MAX_FILENAME + 1);
  strncpy (attach.orig_fname, SURVEY_XML_FNAME, MAX_FILENAME + 1);
  if (write (info_fd, &attach, attachment_size) != attachment_size)
	cs_critical_error (ERR_FWRITE_FAILED, "on info file");


   if(write (info_fd,&person, sizeof(NEWS_PERSON))!= sizeof(NEWS_PERSON))
        cs_critical_error (ERR_FWRITE_FAILED, "on info file");
        
   close (info_fd);

   release_lock(inbox_fd);     /* shared_lock.c */
   fclose(inbox_fp);
   
   write_user_inbox_record(msg_id, time_sent); 
}








/** The selected survey needs to be copied into a new
*** directory under the sender's 'surveys' directory.
*** A file named SURVEY_RELEASE_FNAME, which records the
*** results time is also created within that new directory.
*** Returns name of  the newly created directory in 
*** 'directory_fname'
***/

static
void create_survey_dir(const char *survey_id, time_t results_time,  
                                     const char *username, 
                                time_t *time_sent, char *directory_fname, int student_count)
{
 char src_path[MAX_PATH + 1];
 char dest_path[MAX_PATH + 1];
 char dest_dir[MAX_PATH + 1];
 SURVEY_RELEASE_RECORD survey_info;    
 FILE *fp;
 
  /*** create a randomly named directory to hold the survey files ***/
 
  get_unique_fname (directory_fname, discussion_path, NORMAL_WEBSITE_DIR_PREFIX, time_sent);
  snprintf (dest_dir, MAX_PATH + 1, "%s%s", discussion_path, directory_fname);
  unlink(dest_dir);                        /* because get_unique_fname() created the file */
  if(mkdir (dest_dir, 0777))
       cs_critical_error(ERR_ERROR_CREATING_SURVEY_DIRECTORY, dest_dir);
   
  snprintf(dest_path,MAX_PATH + 1, "%s/%s", dest_dir, SURVEY_XML_FNAME);
  
  
  snprintf(src_path, MAX_PATH + 1, "../%s/_%s_/%s/%s",  SURVEY_DIR, ADMIN_DIR,survey_id, SURVEY_XML_FNAME);
  
  copy_file(src_path, dest_path);     /* shared_copy_file.c */

  /* now write the info file, which records when the teacher can see the results */
 survey_info.results_time = results_time;
 survey_info.student_view_results = ALLOW_STUDENTS_TO_VIEW_RESULTS;
 survey_info.student_view_again = ALLOW_STUDENTS_TO_VIEW_SURVEY_AGAIN;
 survey_info.student_answer_required =STUDENT_ANSWER_REQUIRED;
 survey_info.future2  = 0;
 
 snprintf(dest_path, MAX_PATH + 1, "%s/%s", dest_dir, SURVEY_RELEASE_FNAME);
 fp = fopen(dest_path, "w");
 if(!fp)
    cs_critical_error(ERR_FOPEN_WRITE_FAILED, dest_path);
 if(fwrite(&survey_info, sizeof(SURVEY_RELEASE_RECORD), 1, fp) != 1)
     cs_critical_error(ERR_FWRITE_FAILED, dest_path);
 fclose(fp);
 
 

 /* create the results file, with a few opening tags */ 
 snprintf(dest_path, MAX_PATH + 1, "%s/%s", dest_dir, SURVEY_RESULT_FNAME);
 fp = fopen(dest_path, "w");
 if(!fp)
    cs_critical_error(ERR_FOPEN_WRITE_FAILED, dest_path);

 fprintf(fp, "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>\n");
 fprintf(fp, "<records>\n");
 fprintf(fp, "  <expect_takers>%d</expect_takers>\n", student_count);
 fprintf(fp, SURVEY_RESULT_END_TAG);
 fclose(fp);
  
 
 
}        
    
     
     
static void
get_teacher_info(CONFIG_STRUCT *conf, P_NODE *teacher, const char *username, int *number_students)
{
 P_NODE *head, *ptr;
 int found = 0;
 char error[MAX_PATH +1];
 
 head = build_option_person_list(conf);   /* shared_person_list.c */
 *number_students = count_students(head);           /* shared_person_list.c */
 for(ptr = head; ptr; ptr = ptr->next)
 {
      if(!strcmp(ptr->data.username, username) && ptr->data.group == FACULTY)
      {
	  strncpy(teacher->data.username, ptr->data.username, MAX_USERNAME +1);
	  strncpy(teacher->data.realname, ptr->data.realname, MAX_NAME +1);
	  strncpy(teacher->data.id, ptr->data.id, MAX_ID +1);
	  teacher->data.group = ptr->data.group; 
	  teacher->data.team = ptr->data.team;
	  found = 1;
      }

 }
 
 free_option_person_list(head);          /* shared_person_list.c */
 
 if(!found)
 {
     snprintf(error, MAX_PATH + 1,  
		 "No teacher with username: %s in course %s\n", username, conf->course_path);
     cs_critical_error(ERR_GENERAL_ERROR, error);
 } 
		     
} 
  






static void
write_config_file(CONFIG_STRUCT *conf)
{
    char fname[MAX_PATH +1];
    FILE *fp;

    snprintf (fname, MAX_PATH + 1, "%s%s", conf->course_path, CONFIG_FNAME);
    fp = fopen (fname, "w");
    if (!fp)
        cs_critical_error(ERR_FOPEN_WRITE_FAILED, fname);    /* shared_cs_util.c */
     get_exclusive_lock(fileno(fp), 1);
     if (fwrite (conf, sizeof (CONFIG_STRUCT), 1, fp) != 1)
     {
        release_lock(fileno(fp));
        fclose (fp);
        cs_critical_error(ERR_FWRITE_FAILED, fname);         /* shared_cs_util.c */ 
     }
     release_lock(fileno(fp));
    fclose (fp);

}





static
void create_survey_dirs(CONFIG_STRUCT *conf)
{

P_NODE *head, *ptr;
char survey_central_inbox_dir[MAX_PATH + 1];

  snprintf (survey_central_inbox_dir, MAX_PATH + 1, "%s%s/%s/", conf->course_path, INBOXES_DIR, SURVEYS_DIR);
  if(!file_exists(survey_central_inbox_dir)) /* shared_file_util.c */
   {
     mkdir(survey_central_inbox_dir,0770);          /* create courses/sample/inboxes/surveys directory */

     /* for each user, create courses/sample/people/username/surveys directory */
     head = build_option_person_list(conf);   /* shared_person_list.c */
     for(ptr=head; ptr; ptr=ptr->next)
         create_module_directory(conf->course_path, ptr->data.username,SURVEYS_DIR);  /* shared_add_util.c */
     free_option_person_list(head);   /* shared_person_list.c */
   }  
}






void
print_success(const char *course,  const char *subject, 
		        time_t *result_time, SCHED_DATES *sched_date,
		        const char *username, const char *survey_id)
{
      char time_string[MAX_TIMESTRING +1];

      send_content_type();
      printf("Course: %s\n", course);
      printf("Subject: %s\n", subject);
      printf("Teacher Username: %s\n", username);
      printf("Survey ID: %s\n", survey_id);
      strftime(time_string, MAX_TIMESTRING,DOW_DATE_TIME_FORMAT, localtime(result_time));
      printf("Result_time: %s\n", time_string);
      strftime(time_string, MAX_TIMESTRING,DOW_DATE_TIME_FORMAT, localtime(&(sched_date->start_time)));
      printf("Start_time: %s\n", time_string);
      strftime(time_string, MAX_TIMESTRING,DOW_DATE_TIME_FORMAT, localtime(&(sched_date->end_time)));
      printf("End_time: %s\n\n\n", time_string);

}



static
void check_survey(const char *survey_id)
{
 char survey_path[MAX_PATH + 1];
 char error_msg[500];

  snprintf(survey_path, MAX_PATH + 1, "../%s/_%s_/%s/%s",  SURVEY_DIR, ADMIN_DIR,survey_id, SURVEY_XML_FNAME);

  if(!file_exists(survey_path))     /* shared_file_util.c */
    {
     snprintf(error_msg, 500, "A survey with id: %s doesn't exist.  I looked in: %s", survey_id, survey_path);
     cs_critical_error(ERR_GENERAL_ERROR, error_msg);
    }
}    











int
main (void)
{
  char course[MAX_PATH + 1];	  /* from crs=? command line */
  char subject[MAX_SUBJECT +1];   /* from (optional) subject= command line */
  char *msg_body = 0;             /* from (optional) msg = command line */
  time_t result_time;             /* from result_time= command line */  
  
  SCHED_DATES sched_date;         /* the start_time and end_time for this message - 
                                  ** derived from "start_time" and "end_time" command line
                                  ** parameters
                                  */
  
  char username[MAX_USERNAME +1];     /* from username=? command line */
  char survey_id[MAX_PATH + 1];       /* from survey_id = command line - name of survey to be copied */
  

  char survey_dir[MAX_FILENAME + 1];  /* mkstemp() name given to the  directory where the survey
                                      ** xml files are copied
                                      */
  time_t  time_sent;
  char msg_fname[MAX_FILENAME + 1];   /* mkstemp() name given to the msg file */
  int number_students;                /* how many students are in this class ? */                               
  P_NODE teacher_node;

  CONFIG_STRUCT conf;		      /* the configuration read from config file */
  




  cs_cgi_init();    /* shared_cs_util.c */

  read_parameters (course,&result_time,&sched_date, username, survey_id, subject, &msg_body);

		        
  read_configuration_file (course, &conf);	                       /* shared_util.c */
  set_discussion_names (conf.course_path, username, SURVEYS);	       /* shared_news_util.c */
  get_teacher_info(&conf, &teacher_node, username, &number_students);  /* is 'username' a teacher in course? */
  check_survey(survey_id);                                             /* does the survey exist? */


  /* If the Surveys module for this course is not activated,
  ** then turn it on
  */
  if(!conf.surveys)  
  {
       conf.surveys = 2;         /* 2 means activate the module, and allow users to hide/unhide messages */
       write_config_file(&conf);
       create_survey_dirs(&conf);
  }

  
  


  time_sent = time (NULL);                                      /* sets time_sent to current time */
  process_message_file (msg_body, msg_fname, &time_sent);       /* writes the contents of the message to a file */


  create_survey_dir(survey_id, result_time,  username, &time_sent, survey_dir, number_students);


  
  complete_send(msg_fname,&teacher_node,time_sent, subject, survey_dir, &sched_date);

  if(msg_body)
      free(msg_body);
      
  print_success(course,  subject, &result_time, &sched_date, username, survey_id);

  cs_cgi_destroy();        /* shared_cs_util.c */
  return 0;
}

