#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>


#include "global.h"

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_super_util.h"
#include "manhat-lib/shared_strtrm.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_access.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_file_util.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_super_menu.h"

typedef struct access_node
  {
   CONFIG_STRUCT conf;
   char dirname[MAX_FILENAME + 1];
   int orig_access;   /* value of the original access setting */
   int read_ok;       /* were we able to read the configuration file? */
   struct access_node *next;
  } ACCESS_NODE;
  
ACCESS_NODE *
get_access_node(char *str)
{	
   ACCESS_NODE *ptr;

   ptr = (ACCESS_NODE*)malloc(sizeof(ACCESS_NODE));
   strncpy(ptr->dirname, str, MAX_FILENAME + 1);
   strtrm(ptr->dirname);    /* shared_strtrm.c */
   ptr->next = 0;
   return ptr;
}
   



ACCESS_NODE *
build_access_course_list()
{
   #define MAX_TMP_NAME 50
      ACCESS_NODE *head = 0, *current =0, *ptr;
      char  *str;
      HDF *obj;


      str = hdf_get_value(global_cgi->hdf, "Query.crs.0",  0);
      if(str)
      {
	    obj = hdf_get_child(global_cgi->hdf, "Query.crs");
	    while(obj)
	    {
		  str = obj->value;
		  if(str && strlen(str))
		  {
                    ptr = get_access_node(str);
	            if(!head)
	               head = ptr;
	            else
	            current->next = ptr;
	           current = ptr;
		  }
	          obj = obj->next;
	    }
      }
      else
      {
         str = hdf_get_value(global_cgi->hdf, "Query.crs",  0);
	 if(!str)
           cs_critical_error(ERR_PARAM_MISSING, "crs");
          head = get_access_node(str);
      }
    return head;
   #undef MAX_TMP_NAME 
}


void
free_access_course_list(ACCESS_NODE *head)
{
 ACCESS_NODE *ptr;
 
 while(head)
 {
  ptr = head;
  head = head->next;
  free(ptr);
 }

}



ACCESS_NODE*
read_parameters (char *key, int *access)
{
  ACCESS_NODE  *head;
  char tmp[10 + 1];

  cs_get_required_parameter ("id", key, MAX_KEY);   /* shared_cs_util.c */
  cs_get_required_parameter ("access", tmp,10);/* shared_cs_util.c */
  *access = atoi(tmp);
  head = build_access_course_list();
  return head;
}





void
set_results(ACCESS_NODE *head, const char *key)
{
#define MAX_TMP_NAME 50
  ACCESS_NODE *ptr;
  char url[MAX_PATH +1];
  char name[MAX_TMP_NAME];
  int i =0;

  snprintf(url, MAX_PATH +1, "%s?id=%s", "super_config_course_list", key);
  cs_set_value("back_url", url);
      
  for(ptr=head; ptr; ptr=ptr->next)
  {
       snprintf(name, MAX_TMP_NAME, "chg_course.%d.dirname", i);
       cs_set_value(name, ptr->dirname);
       if(ptr->read_ok)
       {
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.read_ok", i);
          cs_set_int_value(name, 1);
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.course_no", i);
          cs_set_value(name, ptr->conf.course_no);
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.title", i);
          cs_set_value(name, ptr->conf.title);
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.instructor", i);
          cs_set_value(name, ptr->conf.instructor);
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.semester", i);
          cs_set_value(name, ptr->conf.semester);
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.orig_access", i);
          cs_set_int_value(name, ptr->orig_access); 
          snprintf(name, MAX_TMP_NAME, "chg_course.%d.access", i);
          cs_set_int_value(name, ptr->conf.access); 
       }
      i++;
  }
#undef MAX_TMP_NAME
}

   


ACCESS_NODE *
read_configs(ACCESS_NODE *head)
{
 ACCESS_NODE *ptr;
 
 for(ptr=head; ptr; ptr=ptr->next)
  {
   ptr->read_ok = read_configuration_file_ok(ptr->dirname, &(ptr->conf));   /* shared_util.c */
   if(ptr->read_ok)
      ptr->orig_access = ptr->conf.access;
  }    
 return head;
}



static 
void write_new_config_file(const char *fname, CONFIG_STRUCT *conf, const char *extension)
{
  FILE *fp;
  int fd;
  char fullpath[MAX_PATH + 1];

  /* if the first letter of the course fname starts with a 'T',
     ** then this is a course template and the config file will be
     ** located in the TEMPLATE_PATH directory instead of the 
     ** COURSE_PATH directory
   */
  snprintf (fullpath, MAX_PATH + 1, "%s%s/%s%s",
	    (*fname == 'T')? TEMPLATE_PATH : COURSE_PATH, fname, CONFIG_FNAME, extension);

  fp = fopen (fullpath, "w");
  if (fp)
    {
      fd = fileno(fp);
      get_exclusive_lock(fd, 1);    /* shared_lock.c */
  
      fwrite (conf, sizeof (CONFIG_STRUCT), 1, fp);
      release_lock(fd);    /* shared_lock.c */
      fclose (fp);
     }
}



/**
** this is just like read_configuration_file() in shared_util.c
** except it's reading from config.dat.orig
** and that config.dat.orig is DELETED after a successful read
**
** this could (should) be improved so that only the modules that
** are activated are updated, not the entire configuration
*/

int
read_orig_config (const char *fname, CONFIG_STRUCT * config)
{
  FILE *fp;
  int fd;
  char fullpath[MAX_PATH + 1];
  int is_template;
  
  /* if the first letter of the course fname starts with a 'T',
     ** then this is a course template and the config file will be
     ** located in the TEMPLATE_PATH directory instead of the 
     ** COURSE_PATH directory
   */
  is_template = (*fname == 'T');
  snprintf (fullpath, MAX_PATH + 1, "%s%s/%s.orig",
	    is_template ? TEMPLATE_PATH : COURSE_PATH, fname, CONFIG_FNAME);

  fp = fopen (fullpath, "r");
  if (!fp)
      return 0;
          
  /* the config file can be changed by a teacher or administrator
  ** so we use advisory file locking 
  */  
  fd = fileno(fp);
  get_shared_lock(fd, 1);    /* shared_lock.c */
  
  if (fread (config, sizeof (CONFIG_STRUCT), 1, fp) != 1)
   {
    release_lock(fd);
    fclose(fp);
    return 0;
   } 

  release_lock(fd);    /* shared_lock.c */
  fclose (fp);

  /* whether the course is a template or not is NOT stored in the file..
     ** instead it is set here based on the course name
   */
  config->template = is_template;

  /* the course_path data item used to be saved in the file  since the
     ** addition of the course templates idea, it is more convenient to set
     ** it here
   */

  snprintf (config->course_path, MAX_PATH + 1, "%s%s/",
	    is_template ? TEMPLATE_PATH : COURSE_PATH, fname);

  unlink(fullpath);  /* we're done with the backup file */
  return 1;   /* success */
}




/* just check to see if the inbox.dat file exists
** This means at least one message was sent.
** This should be improved to check to make sure there's
** at least one undeleted message in the inbox file
*/
int has_content(const char *course_path, int group)
{
 
 char inbox_fname[MAX_PATH + 1];
 
 /* we're only interested in the 'central_discussion_path' value,
 ** so we can send set_discussion_names() a phony username 
 **/
 set_discussion_names(course_path, "bogus_name", group);    /* shared_news_util.c */
 snprintf(inbox_fname,MAX_PATH + 1,"%s%s",central_discussion_path,INBOX_FNAME);
 if(file_exists(inbox_fname))   /* shared_file_util.c */
      return 1;
 else
      return 0;
}           



int 
has_chat_transcripts(const char *course_path)
{
 char path[MAX_PATH + 1];
 struct stat buf;
 
 
 snprintf (path, MAX_PATH + 1, "%s/%s", course_path, CHAT_MSG_LOG);
 if (!stat (path, &buf) && buf.st_size)     /* file exists and is not empty */
     return 1;
  else
     return 0;
}



int grades_posted(CONFIG_STRUCT *conf)
{

   P_NODE *person_head = 0;
   P_NODE *ptr;
   char teacher_username[MAX_USERNAME + 1];
   char fname[MAX_PATH + 1];
      
   *teacher_username = '\0';
   /* find a teacher */
   person_head = build_option_person_list(conf);    /* shared_person_list.c */
   for(ptr = person_head; ptr; ptr=ptr->next)
     if(ptr->data.group == FACULTY)
       {
        strncpy(teacher_username, ptr->data.username, MAX_USERNAME + 1);
        break;
       }
         
    free_option_person_list(person_head);   /* shared_person_list.c */     
   if(*teacher_username)        
   {
    snprintf (fname, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path,
	    PEOPLE_DIR,teacher_username, GRADES_DIR, GRADES_HTML_FNAME);
    if(file_exists(fname))    /* shared_file_util.c */
       return 1;
    else
       return 0;
   }
   else
       return 1;   /* no teacher - should never happen, but we'll activate the module to be safe */       

  return 1;

}        

static
void activate_modules_with_content(CONFIG_STRUCT *conf)
{

conf->assignments = has_content(conf->course_path, ASSIGNMENTS);
conf->syllabus    = has_content(conf->course_path, HANDOUTS_NOTICES);
conf->discussion =  has_content(conf->course_path, CLASS_DISCUSSION);

conf->postoffice =  1;    /* don't know which user we'll be capturing, best we can do is to always enable the Post Office */

conf->internet   = has_content(conf->course_path, INTERNET_RESOURCES);
conf->lounge     = has_content(conf->course_path, STUDENT_LOUNGE);
conf->chat       = has_chat_transcripts(conf->course_path);
conf->anonymous  = has_content(conf->course_path, ANONYMOUS_DISCUSSION);
conf->team       = has_content(conf->course_path, TEAM_DISCUSSION);
conf->team_teach = has_content(conf->course_path, TEAM_TEACH);

conf->grades     = grades_posted(conf);

conf->selftest   = has_content(conf->course_path, SELFTEST);
conf->lectures   = has_content(conf->course_path, LECTURES);

}


ACCESS_NODE *
write_new_configs(ACCESS_NODE *head, int access)
{
 ACCESS_NODE *ptr;
 
 for(ptr=head; ptr; ptr=ptr->next)
  {
   if(ptr->read_ok)
    {
      
      if( (access == ACCESS_CAPTURE) && (ptr->orig_access != ACCESS_CAPTURE))  /* if changing TO capture mode */
          {
            write_new_config_file(ptr->dirname, &(ptr->conf), ".orig");   /* backup original configuration to config.dat.orig */
            activate_modules_with_content( &(ptr->conf));   /* turn on all modules that have messages */
          }  
      else
        if( (access != ACCESS_CAPTURE) && (ptr->orig_access == ACCESS_CAPTURE))   /* if changing FROM capture mode */
            read_orig_config(ptr->dirname, &(ptr->conf));           /* restore original module selections from config.dat.orig file
                                                                    ** and delete the config.dat.orig backup file
                                                                    */
      
      ptr->conf.access = access;
      write_new_config_file(ptr->dirname, &(ptr->conf), "");
    }
  }
 return head;
}

   

int
main ()
{

  char key[MAX_KEY + 1];	/* from id=? command line */
  ACCESS_NODE *head;
  int access;                   /*from access=? command line */
  SESSION user;
 
  cs_cgi_init(); 

  head = read_parameters (key, &access);
  validate_super_key (key, &user);	/* shared_super_util.c */
  set_admin_page(&user, key, 0, "super_config_course_list");  /* shared_super_menu.c */

  head = read_configs(head);      /* read the configuration file for each course */
  head = write_new_configs(head, access);
  set_results(head, key);
  free_access_course_list(head);
  cs_cgi_display("super_chg_crs_access", 1);
  cs_cgi_destroy();  
  return 0;
}

