#include <stdio.h>
#include <sys/stat.h>		/** for stat() */
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>


#include <ClearSilver.h>

#include "global.h"

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_grades_util.h"
#include "manhat-lib/shared_unread.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_login.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_authenticate.h"  
#include "manhat-lib/shared_server_locked.h"
#include "manhat-lib/shared_strtrm.h"
#include "manhat-lib/shared_access.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_file_util.h"
#include "manhat-lib/shared_drop_add_list.h"
#include "manhat-lib/shared_survey_take_verify.h"
#include "manhat-lib/shared_system_data.h"


static int
button_count (CONFIG_STRUCT *conf)
{
  int button_count = 0;

  if (conf->assignments)
    button_count++;
  if (conf->syllabus)
    button_count++;
  if (conf->discussion)
    button_count++;
  if (!conf->template && conf->postoffice)
    button_count++;
  if (conf->internet)
    button_count++;
  if (!conf->template && conf->lounge)
    button_count++;
  if (!conf->template && conf->chat)
    button_count++;
  if (!conf->template && conf->anonymous)
    button_count++;
  if (!conf->template && conf->team)
    button_count++;
  if (!conf->template && conf->team_teach)
    button_count++;
  if (!conf->template && conf->grades)
    button_count++;
  if (conf->selftest)
    button_count++;
  if (conf->lectures)
    button_count++;
  if (conf->people)
       button_count++;
  if (conf->surveys)
        button_count++;       
  if (conf->podcasts)
        button_count++;       
  if(conf->calendar)
        button_count++;        
  if(conf->testpilot)
        button_count++;        

  return button_count;

}




static
void set_module_values(int unread, int count, int module, char *name, 
                             CONFIG_STRUCT *conf, SESSION *user, time_t current_time, const char *course,
                             const char *key)
{
 char node_name[MAX_PATH + 1];
 char url[MAX_PATH + 1];
 
 if(unread == -1)
     unread = unread_news (user, module, conf, current_time); /*shared_unread.c*/
  snprintf(node_name, MAX_PATH + 1, "item.%d.module", count);
  cs_set_value( node_name, name);

  snprintf(node_name, MAX_PATH + 1, "item.%d.is_unread", count);
  cs_set_int_value(node_name, unread? 1 : 0);
  
  
  switch(module)
  { 
    case CLASS_DISCUSSION:
    case STUDENT_LOUNGE:
    case ANONYMOUS_DISCUSSION:
    case TEAM_DISCUSSION:
    case HANDOUTS_NOTICES:
    case INTERNET_RESOURCES:
    case ASSIGNMENTS:
    case TESTPILOT:
    case SELFTEST:
    case LECTURES:
    case PODCASTS:
    case SURVEYS:  snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s&amp;grp=%d","news_topic", course, key,module); 
                   break;
    
    
    case TEAM_TEACH: if(user->group == FACULTY)
                      snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s","news_team_list", course, key);
                     else
                      snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s&amp;grp=%d","news_topic", course, key, module);
                     break;
                     
                      
   case CHATTER:     snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s","chat_transcript", course, key);                    
                     break;   
                      
   case MAIL:        snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s","post_inbox", course, key);                    
                     break;
                    
   case GRADES:      if(user->group == FACULTY )
		     {
		       if(conf->grades == 2 )
                              snprintf(url, MAX_PATH + 1,"%s?crs=%s&amp;id=%s","grade_book", course, key);      
	               else	       
                          snprintf(url, MAX_PATH + 1,"%s?crs=%s&amp;id=%s","grades_fac_menu", course, key);      
		     }
                    else
		    { 
			    if(conf->grades == 1)
                                 snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s","grades_view", course, key);   
			    else if(conf->grades == 3)
                                 snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s","gradequick_view", course, key);   

                            else 		    
                                 snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", "grade_book_std", course, key);    
		    } 
                     break;

   case PEOPLE:      snprintf(url, MAX_PATH + 1," %s?crs=%s&amp;id=%s","bio_list", course, key);                    
                     break;
                  
   case CALENDAR:      snprintf(url, MAX_PATH + 1," %s?crs=%s&amp;id=%s","calendar", course, key);                    
                     break;
                  
   default:          snprintf(url, MAX_PATH + 1, "unknown module");                                  
                     break;
  }                 
 
  snprintf(node_name, MAX_PATH + 1, "item.%d.url", count);
  cs_set_value(node_name, url);       
  
}

  
  


static void
insert_button (int feature, char *course,
	       char *key, CONFIG_STRUCT *conf, SESSION *user, time_t current_time)
{
  static int count = 0;
  char node_name[MAX_PATH + 1];
  int unread;


  snprintf(node_name, MAX_PATH + 1, "item.%d.module", count);
  switch (feature)
    {
    case ASSIGNMENTS: 	set_module_values(-1, count, ASSIGNMENTS, "assign", conf, user, current_time, course, key); 
    			break;

    case TESTPILOT: 	set_module_values(-1, count, TESTPILOT, "testpilot", conf, user, current_time, course, key); 
    			break;

    case LECTURES:    	set_module_values(-1, count, LECTURES, "lectures", conf, user, current_time, course, key); 
    			break;

    case HANDOUTS_NOTICES: 	set_module_values(-1, count, HANDOUTS_NOTICES, "handouts", conf, user, current_time, course, key); 
    				break;
    case INTERNET_RESOURCES: 	set_module_values(-1, count, INTERNET_RESOURCES, "inet", conf, user, current_time, course, key); 
    				break;
    case CLASS_DISCUSSION: 	set_module_values(-1, count, CLASS_DISCUSSION, "class", conf, user, current_time, course, key); 
    				break;
    case STUDENT_LOUNGE: 	set_module_values(-1, count, STUDENT_LOUNGE, "lounge", conf, user, current_time, course, key); 
    				break;
    case ANONYMOUS_DISCUSSION: 	set_module_values(-1, count, ANONYMOUS_DISCUSSION, "anon", conf, user, current_time, course, key); 
    				break;
    case TEAM_DISCUSSION: 	set_module_values(-1, count,  TEAM_DISCUSSION, "team", conf, user, current_time, course, key); 
    				break;
    case TEAM_TEACH: 	set_module_values(-1, count,  TEAM_TEACH, "teamteach", conf, user, current_time, course, key); 
    			break;
    case SELFTEST: 	set_module_values(-1, count,  SELFTEST, "selftest", conf, user, current_time, course, key); 
    			break;
    case SURVEYS: 	set_module_values(-1, count, SURVEYS, "surveys", conf,user,  current_time, course, key); 
    			break;
    
    case CHATTER:
      unread = system_data_int("SHOW_REDSTAR_ON_CHAT_BUTTON") && non_empty_chatroom (); /* shared_unread.c */
      set_module_values(unread, count, CHATTER, "chat", conf, user,  current_time, course, key);
      break;

    case MAIL:
      unread = unread_mail (user->username, conf); /* shared_unread.c */
      set_module_values(unread, count, MAIL, "post", conf, user,  current_time, course, key); 
      break;

    case GRADES:
      if (user->group==FACULTY)
	update_grades_inf (conf, user->username);	/* shared_grades_util.c */
      unread = unread_grades (user->username, conf); 	/* shared_unread.c */	  
      set_module_values(unread, count, GRADES, "grades", conf, user,  current_time, course, key); 
      break;

    case PEOPLE:
      cs_set_value(node_name, "people");
      set_module_values(0, count, PEOPLE, "people", conf, user,  current_time, course, key);
      break;

    case PODCASTS:
      cs_set_value(node_name, "podcasts");
      set_module_values(-1, count, PODCASTS, "podcasts", conf, user,  current_time, course, key); 
      break;

    case CALENDAR:
      cs_set_value(node_name, "calendar");
      set_module_values(0, count, CALENDAR, "calendar", conf, user,  current_time, course, key);
      break;

    default:
      break;

    }
  count++;
}




static void
setup_main_menu (char *course_name, char *key, char *username,
		   CONFIG_STRUCT *conf, SESSION *user)
{
  time_t current_time;
  char url[MAX_PATH + 1];
  
  current_time = time(NULL);
  
  cs_set_int_value("classroom_locked", CLASSROOM_LOCKED(conf->misc)? 1 : 0);
  cs_set_int_value ( "button_count", button_count(conf));  

  cs_set_course_info(conf);   /* shared_cs_util.c */

  cs_set_int_value( "is_faculty", user->group == FACULTY? 1 : 0); 

  if (conf->assignments)
    insert_button (ASSIGNMENTS, course_name, key, conf, user, current_time);

  if (conf->testpilot)
    insert_button (TESTPILOT, course_name, key, conf, user, current_time);

  if (conf->lectures)
    insert_button (LECTURES, course_name, key, conf, user, current_time);

  if (conf->syllabus)
    insert_button (HANDOUTS_NOTICES, course_name, key, conf, user, current_time);

  if (conf->internet)
    insert_button (INTERNET_RESOURCES, course_name, key, conf, user, current_time);

  if (conf->selftest)
    insert_button (SELFTEST, course_name, key, conf, user, current_time);

  if (!conf->template && conf->chat)
    insert_button (CHATTER, course_name, key, conf, user, current_time);

  if (!conf->template && conf->postoffice)
  {
    insert_button (MAIL, course_name, key, conf, user, current_time);
  }
  if (conf->discussion)
    insert_button (CLASS_DISCUSSION, course_name, key, conf, user, current_time);

  if (!conf->template && conf->lounge)
    insert_button (STUDENT_LOUNGE, course_name, key, conf, user, current_time);

  if (!conf->template && conf->anonymous)
    insert_button (ANONYMOUS_DISCUSSION, course_name, key, conf, user, current_time);

  if (!conf->template && conf->team)
    insert_button (TEAM_DISCUSSION, course_name, key, conf, user, current_time);

  if (!conf->template && conf->team_teach)
    insert_button (TEAM_TEACH, course_name, key, conf, user, current_time);

  if (!conf->template && conf->grades)
    insert_button (GRADES, course_name, key, conf, user, current_time);

  if (!conf->template && conf->people)
    insert_button (PEOPLE, course_name, key, conf, user, current_time);

  if (!conf->template && conf->surveys)
    insert_button (SURVEYS, course_name, key, conf, user, current_time);

  if (conf->podcasts)
    insert_button (PODCASTS, course_name, key, conf, user, current_time);
 
  if (conf->calendar)
    insert_button (CALENDAR, course_name, key, conf, user, current_time);

  if( (user->group == FACULTY && ( system_data_int("ALLOW_TEACHER_CHANGE_PASSWORD") && conf->access != ACCESS_CAPTURE)) || 
           system_data_int("ALLOW_STUDENT_CHANGE_PASSWORD")) /* shared_system_data.h */
        snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", "passwd_form", course_name, key);      
  else
       *url = '\0';      
  cs_set_value("change_password_url", url);
    
  if(conf->access == ACCESS_CAPTURE)
     *url = '\0';
  else
       snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", "logout", course_name, key);
  cs_set_value("exit_url", url);
    
  if(user->group == FACULTY)
     snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", "admin_main_menu", course_name, key);  
  else
     *url = '\0';   
  cs_set_value("config_url", url);
  snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", "calendar", course_name, key);  
  cs_set_value("calendar_url", url);
}





    
static void
read_parameters (char *course, char *key, int *from_mymanhat)
{
 char tmp[11];
 
 cs_get_required_parameter("crs", course, MAX_PATH); 	/* shared_cs_util.c */
 cs_get_required_parameter("id", key, MAX_KEY); 	/* shared_cs_util.c */
 cs_get_optional_parameter("mymanhat",tmp, 10);         /* shared_cs_util.c */
 *from_mymanhat = (*tmp == '1')? 1 : 0; 
}




static void
empty_classroom_message ()
{
  cs_critical_error(ERR_NO_MODULES_SELECTED, "");   /* shared_cs_util.c */
}





static
int course_listed(const char *username, const char *course, char dir)
{
#define MAX_LINE 200

 char course_file[MAX_PATH + 1];
 FILE *fp;
 int fd; 
 char line[MAX_LINE];
 int found = 0;

  snprintf(course_file, MAX_PATH + 1, "../%s/%c/%s/%s",
                            USERS_DIR, dir, username,COURSE_LIST_FNAME);
  fp = fopen(course_file, "r"); 
  if(!fp)
   return 0;    

  fd = fileno(fp);
  get_shared_lock(fd, 1);   		/* shared_lock.c */
 
  while(fgets(line,MAX_LINE,fp) && !found)
  {
    strtrm(line);  			/* shared_strtrm.c */
    found = !strcmp(line,course);
  }
  release_lock(fd);   			/* shared_lock.c */
  fclose(fp);    
  return found;

#undef MAX_LINE  
}  




static
void course_login(SESSION *user, const char *course, const char *keypath, CONFIG_STRUCT *conf)
{
 FILE *fp;
 
 
 if(!get_user_info ( user->username, user, conf))    		/* shared_person_list.c */
   cs_critical_error (ERR_REQUEST_DENIED, "course_login()");    /* shared_cs_util.c */
 
 
 remove_stale_symlinks (user->username, course, conf->access);  /* shared_news_util.c */
// kill_hotpotato_directory(username, &(course_ptr->conf));   	/* shared_potato_util.c */
 
 /** write the course specific SESSION info for this user
 *** to a file named course.key in the user's central directory
 **/
 
 fp = fopen(keypath, "w");
 if(!fp)
       cs_critical_error(ERR_FOPEN_WRITE_FAILED, keypath);    /* shared_cs_util.c */
 if(fwrite(user, sizeof(SESSION), 1, fp) != 1)
       cs_critical_error(ERR_FWRITE_FAILED, keypath);         /* shared_cs_util.c */ 
 fclose(fp);
 
 log_this_access (user->username, conf->course_path,PEOPLE_DIR);      /* shared_login.c */
}





static
void validate_key_login(const char *key, SESSION *user, const char *course, CONFIG_STRUCT *conf)
{
 char dir;
 FILE *fp;
 char keypath[MAX_PATH + 1];
 char modified_course[MAX_PATH + 1];
  
   validate_server_key (key, user);      		/* shared_util.c */
   
   dir = sub_dir_name(user->username);   		/* shared_authenticate.c */
     
   course_slash_to_dot(course, modified_course);      	/* shared_util.c */

   snprintf(keypath, MAX_PATH + 1, "../%s/%c/%s/%s%s",
                            USERS_DIR, dir, user->username,
                            			modified_course,KEY_FILE_EXTENSION);

  /* try to read the session file */                            			
   fp = fopen(keypath, "r");
   if(fp)
   {
    if(fread(user,sizeof(SESSION), 1, fp) != 1)
       cs_critical_error (ERR_LOGGED_OUT, "");    /* shared_cs_util.c */
    fclose(fp);
   }
   else   /* session file isn't there - try to log the user in */
    {
      if(!course_listed(user->username, course, dir))
         cs_critical_error (ERR_REQUEST_DENIED, "");   /* shared_cs_util.c */
      course_login(user,course, keypath, conf);
    }  
}



int has_add_drop_list(CONFIG_STRUCT *conf)
{
     char path[MAX_PATH +1];
     char dummy[MAX_PATH +1];
	 P_NODE *head;
	 P_NODE *drop_head, *ptr;
	 int count = 0;

     snprintf(path, MAX_PATH + 1, "%s%s", conf->course_path, ADD_LIST_FNAME);
     if(file_exists(path))   /* shared_file_util.c */
	    return 1;

     snprintf(path, MAX_PATH + 1, "%s%s", conf->course_path, DROP_LIST_FNAME);
     if(file_exists(path))    /* shared_file_util.c */
	 {
	    drop_head =build_drop_person_list (path, dummy,MAX_PATH +1);
        head = build_option_person_list(conf);
        for(ptr = drop_head; ptr; ptr = ptr->next)
		{
		    if(find_student_in_passwd(head, ptr))
			     count++;
		}
	free_option_person_list(drop_head);
	free_option_person_list(head);
        if(count == 0)
		{
		    unlink(path);
			return 0;
		}
	    return 1;
	}

     return 0;
     
}


int has_required_survey(CONFIG_STRUCT *conf, SESSION *user, long *offset)
{

  time_t current_time;
  MSG_TREE_NODE *ptr;
  int found = 0;
  
  *offset = -1;

 if( (user->group != STUDENT) || !(conf->surveys))
    return 0;
    
 set_discussion_names (conf->course_path, user->username, SURVEYS);	     /* shared_news_util.c */
 build_msg_tree(user,SURVEYS,0,0, &current_time);  /* shared_news_util.c */

 if(tree_head)
  {
   for(ptr = tree_head, found = 0; ptr && !found; ptr = ptr->next)
    {
     found = !ptr->user_data.time_read && 
             (BASIC_STATUS(ptr->data.status) != READ_ONLY) &&
             is_unanswered_required_survey(conf, ptr->data.info.sender, ptr->data.info_fname, user);  /* shared_survey_take_verify.c */
     if(found)
        *offset = ptr->offset;
    }
       
   free_msg_tree(tree_head);
  } 
 
 return found? 1 : 0;
 
}






static
void setup_required_survey_page(const char *course, const char *key, long survey_offset, CONFIG_STRUCT *conf)
{
  char url[MAX_PATH + 1];

  cs_set_course_info(conf);   /* shared_cs_util.c */

  snprintf (url, MAX_PATH + 1, "%s?crs=%s&id=%s&loc=%ld&grp=%d\n\n", "news_read", course, key,survey_offset, SURVEYS);
  cs_set_value("take_survey_url", url);
  
  if(conf->access == ACCESS_CAPTURE)
     *url = '\0';
  else   
     snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s", "logout", course, key);
  cs_set_value("exit_url", url);
}

int
main ()
{
  char course[MAX_PATH + 1];	/* from crs=? command line */
  char key[MAX_KEY + 1];	/* from id=? command line */
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */
  int add_drop = 0;
  long offset =0;
  int from_mymanhat;           /* from optional from_mymanhat=? command line */

  cs_cgi_init();    /* shared_cs_util.c */
  
  
  
  read_parameters (course, key, &from_mymanhat);

  read_configuration_file(course, &conf);	/* shared_util.c */
  cs_set_course_info(&conf);    		/* shared_cs_util.c */

          
  if(!conf.standalone)
    validate_key_login(key, &user, course, &conf);
  else
     validate_key (key, &user, &conf);			/* shared_util.c */
  
  if(conf.standalone)
     check_lockout (key, conf.course_path);		/* shared_server_locked.c has system been shut down? */
  else
    central_user_check_lockout(key);                    /* shared_server_locked.c */   


  has_write_permission(&user, &conf);   		/* shared_access.c  - stops with error if user shouldn't be here */

  if(user.group == FACULTY)
      add_drop = has_add_drop_list(&conf);
  else
   {
    if(CLASSROOM_LOCKED(conf.misc))
      empty_classroom_message();
   }    



  if (!modules_enabled (&conf))   			/* shared_news_util.c */
    {
      if (user.group == FACULTY && (from_mymanhat || conf.standalone))        /* redirect teacher to module selection form, if coming from my manhattan page or if standalone course */
	printf ("Location:%s?crs=%s&id=%s&first=1\n\n", "admin_module_form",
		course, key);
      else if(user.group != FACULTY)    /* students get a page saying class is not set up yet */
	    empty_classroom_message ();               
    }


   /* Note teachers might still be here, if no modules are enabled, but they're not coming from my manhattan.
   ** They might be coming from 'admin_module_form' 
   */
   
   if(add_drop)
      printf ("Location:%s?crs=%s&id=%s\n\n", "show_add_drop", course, key);
	
   else if (only_handouts_enabled (&conf))   		/* shared_news_util.c */
      printf ("Location:%s?crs=%s&id=%s&grp=%d\n\n", "news_topic", course, key, HANDOUTS_NOTICES);


   else if ((user.group == STUDENT) && conf.surveys && has_required_survey(&conf, &user, &offset))
    {
      setup_required_survey_page(course, key, offset, &conf);
      cs_cgi_display ("main_menu_required_survey", 1);    /* shared_cs_util.c */
    }
   else
    {
     setup_main_menu (course, key, user.username,  &conf, &user);
     cs_cgi_display ("main_menu", 1);    /* shared_cs_util.c */
    }
    
    
  cs_cgi_destroy();        /* shared_cs_util.c */
  return 0;

}

