#include <stdio.h>
#include <string.h>
#include <ctype.h>

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

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_super_util.h"
#include "manhat-lib/shared_authenticate.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_super_list.h"
#include "manhat-lib/shared_strtrm.h"
#include "manhat-lib/shared_central_user.h"
#include "manhat-lib/shared_escape_realname.h"
#include "manhat-lib/shared_search_profile.h"
#include "manhat-lib/shared_bio.h"
#include "manhat-lib/shared_access.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_super_menu.h"


COURSE_NODE *master_course_head = (COURSE_NODE *) 0;   /* COURSE_NODE is declared in shared_search_profile.h */





static void
set_one_link(const char *key, const char *search, int field, int users, 
	    int report, int sensitive, int sort, int where, int start, int records_per_page,int num)
                    
{
  #define MAX_TMP_NAME 40	

 char url[MAX_PATH +1];
 char name[MAX_TMP_NAME];

 snprintf(name, MAX_TMP_NAME, "page.%d.url", num);
 snprintf(url, MAX_PATH +1, "%s?id=%s&amp;search=%s&amp;field=%d&amp;users=%d&amp;results=%d&amp;sensitive=%d&amp;sort=%d&amp;where=%d&amp;start=%d&amp;step=%d",
           "super_info",
           key,
           search,
           field,
           users,
           report,
           sensitive,
           sort,
           where,
           start,
           records_per_page);
 cs_set_value(name, url);
  #undef MAX_TMP_NAME 

}

           


static
void  print_goto_page_links(int count, const char *search, int field, int users, int report,  
                      				int sensitive, int where, int sort, int start_record, int records_per_page, const char *key)
{
  #define MAX_TMP_NAME 40

  int page;
  int last_page;
  int start;
  int previous_start;
  int next_start;
  char name[MAX_TMP_NAME]; 
  int i =0; 

  /* print previous page link */
  previous_start = start_record - records_per_page;
  if(previous_start >= 1)
  {
     snprintf(name, MAX_TMP_NAME, "page.%d.name", i);
     cs_set_value(name, "<<");
     set_one_link(key,search,field,users,report,sensitive, sort, where, previous_start, records_per_page, i);
     i++;
  }
  

 /*** print numbered pages ***/        
  last_page = count/records_per_page;
  if(count % records_per_page)
     last_page++;

  for(page = 1, start = 1; page <= last_page; page++, start += records_per_page)
   {
    if ((start_record >= start)  && (start_record < (start + records_per_page)))   /* if page == this page */
    {
     snprintf(name, MAX_TMP_NAME, "page.%d.name", i);
     cs_set_int_value(name, page);
    }
    else
     {
       snprintf(name, MAX_TMP_NAME, "page.%d.name", i);
       cs_set_int_value(name, page);
       set_one_link(key,search,field,users,report,sensitive, sort, where, start, records_per_page, i);
     } 
     i++;    
   }  
   
   
   /*** print "next page" link ****/
   next_start =start_record + records_per_page;
   if(next_start > count)
   {
      snprintf(name, MAX_TMP_NAME, "page.%d.name", i);
      cs_set_value(name, ">>");
   }
   else
   {
      snprintf(name, MAX_TMP_NAME, "page.%d.name", i);
      cs_set_value(name, ">>");
      set_one_link(key,search,field,users,report,sensitive, sort, where, next_start, records_per_page, i);
   }   
  #undef MAX_TMP_NAME 
}           
           
           






static void
set_heading(int count, char *search, int field, int users, int report,  
                      int sensitive, int where, int sort, int start_record, int records_per_page, const char *key)
{
    char url[MAX_PATH +1];
    if(count > records_per_page)
    {
        snprintf (url, MAX_PATH +1, "%s?id=%s","super_info_form", key);
        cs_set_value("back_url", url);
    }	
    
    cs_set_value("search", search);
    cs_set_int_value("field", field);
    cs_set_int_value("users", users);
    cs_set_int_value("sensitive", sensitive);
    cs_set_int_value("sort", sort);
    cs_set_int_value("where", where);
    cs_set_int_value("num_match", count);

    if(count)
	cs_set_int_value("showing_from", start_record);
    else
	cs_set_int_value("showing_from", 0);
    
    if((start_record + records_per_page - 1) < count)
	cs_set_int_value("showing_to", (start_record + records_per_page - 1) );
    else
	cs_set_int_value("showing_to", count );
   
   if(records_per_page < count)
       print_goto_page_links(count, search, field, users, report, sensitive, where, sort, start_record, records_per_page, key);
}   

   

void
set_no_search_string(const char *key, PROFILE_NODE *profile_head, int sort)
{
 #define MAX_TMP_NAME 50
 char name[MAX_TMP_NAME];
 char url[MAX_PATH +1];
 PROFILE_NODE *ptr;
 CONFIG_STRUCT dummy_conf;   /* used in call to get_bio_dir() */
 char bio_dir[MAX_PATH + 1];   /* path to a user's bio */
 int i =0;

 for(ptr = profile_head; ptr; ptr=ptr->next)
 {
    get_bio_dir("",&dummy_conf,ptr->person.username, bio_dir);    /* shared_bio.c */
    snprintf(name, MAX_TMP_NAME, "user.%d.username", i);
    cs_set_value(name, ptr->person.username);
    snprintf(url, MAX_PATH +1, "%s?id=%s&amp;search=%s&amp;field=%d&amp;users=%d&amp;results=%d&amp;sort=%d",
                 "super_info", 
                 key, 
                 ptr->person.username,
                 USERNAME_FIELD,
                 ALL_USERS, 
                 FULL_RESULTS,
                 sort);
    snprintf(name, MAX_TMP_NAME, "user.%d.url", i);
    cs_set_value(name, url);
    snprintf(name, MAX_TMP_NAME, "user.%d.realname", i);
    cs_set_value(name, ptr->person.realname);
    snprintf(name, MAX_TMP_NAME, "user.%d.id", i);
    cs_set_value(name, ptr->person.id);
    if(bio_exists(bio_dir))   /* shared_bio.c */
    {
       snprintf(name, MAX_TMP_NAME, "user.%d.bio_url", i);
       snprintf(url, MAX_PATH +1, "/%s/%s?id=%s&amp;user=%s&amp;admin=1",
              ALIAS,
              "bio_view",
              key,
              ptr->person.username);
       cs_set_value(name, url);

    }
    i++; 
 }

 #undef MAX_TMP_NAME 
}	
void
set_search_string(const char *key, PROFILE_NODE *profile_head, int sort, int search_len)
{
 #define MAX_TMP_NAME 50
 char name[MAX_TMP_NAME];
 char url[MAX_PATH +1];
 PROFILE_NODE *ptr;
 CONFIG_STRUCT dummy_conf;   /* used in call to get_bio_dir() */
 char bio_dir[MAX_PATH + 1];   /* path to a user's bio */
 int i =0;

 for(ptr = profile_head; ptr; ptr=ptr->next)
 {
    get_bio_dir("",&dummy_conf,ptr->person.username, bio_dir);    /* shared_bio.c */
    set_highlighted(ptr->person.username, ptr->username_match, search_len, "username", i);   /* shared_search_profile.c */

    snprintf(url, MAX_PATH +1, "%s?id=%s&amp;search=%s&amp;field=%d&amp;users=%d&amp;results=%d&amp;sort=%d",
                 "super_info", 
                 key, 
                 ptr->person.username,
                 USERNAME_FIELD,
                 ALL_USERS, 
                 FULL_RESULTS,
                 sort);
    snprintf(name, MAX_TMP_NAME, "user.%d.url", i);
    cs_set_value(name, url);

    set_highlighted(ptr->person.realname, ptr->realname_match, search_len, "realname", i);  /* shared_search_profile.c */
    set_highlighted(ptr->person.id, ptr->id_match, search_len, "id", i);  /* shared_search_profile.c */
    if(bio_exists(bio_dir))   /* shared_bio.c */
    {
       snprintf(name, MAX_TMP_NAME, "user.%d.bio_url", i);
       snprintf(url, MAX_PATH +1, "/%s/%s?id=%s&amp;user=%s&amp;admin=1",
              ALIAS,
              "bio_view",
              key,
              ptr->person.username);
       cs_set_value(name, url);

    }
    i++; 
 }

 #undef MAX_TMP_NAME 
}


static
void set_quick_list(const char *key, PROFILE_NODE *profile_head, int user_count, 
                                                 char *search, int field, int users,  int sensitive,
                                                 int where, int sort, int results,
                                                 int start_record, int records_per_page)
{
 int search_len;
 
  search_len = strlen(search);

  set_heading(user_count, search, field, users,INDEX_RESULTS, sensitive, where, sort, start_record, records_per_page, key);
 
  if(profile_head)
  {
    if(users == 3 && results==1)
	cs_set_int_value("check_all", 1);
    if(!search_len)   /* if user did not enter a search string */
      set_no_search_string(key, profile_head, sort);
    else  /* search string was not blank, do same as above, but highlight match string */
     set_search_string(key, profile_head, sort, search_len);
  }

 #undef MAX_TMP_NAME 
} 		




static
void get_configuration_data(COURSE_NODE *new_item, const char *crs)
{
 CONFIG_STRUCT conf;
 
  read_configuration_file (crs, &conf);  /* shared_util.c */

  strncpy(new_item->course_data.course_dir, crs, MAX_PATH + 1 );
  strncpy(new_item->course_data.course_no, conf.course_no, MAX_COURSE_NO + 1);
  strncpy(new_item->course_data.title, conf.title, MAX_COURSE_TITLE + 1);
  strncpy(new_item->course_data.semester, conf.semester, MAX_SEMESTER + 1);
  strncpy(new_item->course_data.instructor, conf.instructor, MAX_INSTRUCTOR + 1);
  new_item->course_data.standalone = conf.standalone;
  new_item->course_data.template = conf.template;
  new_item->course_data.access = conf.access;
  new_item->course_data.next = 0;
}

static
void add_user_list(COURSE_NODE *new_item, const char *crs)
{
#define MAXLINE 200

 char passwd_fname[MAX_PATH + 1];
 FILE *fp;
 char line[MAXLINE + 1];
 USER_DATA user_data;
 USERNAME_GROUP_NODE *last = 0;
 
 new_item ->user_head = 0;
 
 snprintf(passwd_fname, MAX_PATH + 1, "%s%s/%s", 
                             *crs == 'T'? TEMPLATE_PATH: COURSE_PATH,
                              crs,
                              PASSWD_FNAME);
 fp = fopen(passwd_fname, "r");
 if(fp)
  {
     get_shared_lock(fileno(fp),1);  /* shared_lock.c */
     while (fgets (line, MAXLINE, fp))
         {
            if (*line == '?')		/* password lines starting with a '?' are ignored */
	       continue;

            if(!new_item->user_head)
             {
              new_item->user_head = (USERNAME_GROUP_NODE *) malloc(sizeof(USERNAME_GROUP_NODE));
              if(!new_item->user_head)
                  cs_critical_error(ERR_MALLOC_FAILED, "");
              last = new_item->user_head;
             }                  
            else
             {
              last->next = (USERNAME_GROUP_NODE *) malloc(sizeof(USERNAME_GROUP_NODE));
              if(!last->next)
                  cs_critical_error(ERR_MALLOC_FAILED, "");
              last = last->next;
             }              

            get_passwd_line_data(line, &user_data);   /* shared_person_list.c */
            strncpy(last->username, user_data.username, MAX_USERNAME + 1);
            last->group = user_data.group;
            last->next = 0;

          }   /* while fgets() */      
       release_lock(fileno(fp));
       fclose(fp);
   }       /* if fp */
#undef MAXLINE
}




static
void get_master_course_list_data(COURSE_NODE *new_item, const char *crs)
{
 get_configuration_data(new_item, crs);
 add_user_list(new_item, crs);
 new_item->next = 0;
}





static
COURSE_NODE *new_master_course_node(const char *crs)
{
 static COURSE_NODE *last_node = (COURSE_NODE *) 0;
 
 if(!master_course_head)
    {
     master_course_head = (COURSE_NODE *) malloc(sizeof(COURSE_NODE));
     if(!master_course_head)
       cs_critical_error(ERR_MALLOC_FAILED, "");
     last_node = master_course_head;
    }
 else
    {
     last_node -> next = (COURSE_NODE *) malloc(sizeof(COURSE_NODE));
     if(!last_node->next)
         cs_critical_error(ERR_MALLOC_FAILED, "");
     last_node = last_node->next;
    }

    get_master_course_list_data(last_node,crs);    
    last_node -> next = 0;
    return last_node;
}               
  






static
GROUP_TYPE teacher_or_student(const char *username, USERNAME_GROUP_NODE *head)
{
 USERNAME_GROUP_NODE *ptr;
 
 for(ptr=head; ptr; ptr=ptr->next)
  if(!strcmp(username, ptr->username))
     return ptr->group;

  return UNKNOWN_GROUP;
}

  


static
void add_course_to_profile(PROFILE_NODE *profile, COURSE_NODE *course_to_add)
{
 USER_COURSE_NODE *ptr;
 
 if(!profile->course_head)
  {
      profile->course_head = (USER_COURSE_NODE *)malloc (sizeof(USER_COURSE_NODE)) ;
      if(!profile->course_head)
          cs_critical_error(ERR_MALLOC_FAILED, "");
      ptr = profile->course_head;
  }
 else
  {
    for(ptr = profile->course_head; ptr->next; ptr=ptr->next);
    ptr->next =  (USER_COURSE_NODE *)malloc (sizeof(USER_COURSE_NODE)) ;
    if(!ptr->next)
         cs_critical_error(ERR_MALLOC_FAILED, "");
    ptr = ptr->next;
  }
         
  ptr->course_data = course_to_add;
  
  ptr->group = teacher_or_student(profile->person.username, course_to_add->user_head);
  ptr->next = (USER_COURSE_NODE *) 0;
}  





static
void add_one_course_data(PROFILE_NODE *profile, COURSE_LIST_NODE *course)
{
  COURSE_NODE *ptr;
  int found = 0;
       
  for(ptr = master_course_head, found = 0; ptr && !found; ptr=ptr->next)
     if(!strcmp(course->crs, ptr->course_data.course_dir))
        {
          found = 1;
          add_course_to_profile(profile, ptr);
        }
           
       
  if(!found)     
   {   
    ptr = new_master_course_node(course->crs);
    
    if(ptr)
      {
        add_course_to_profile(profile, ptr);
      }
    }

}





 
 

static void
add_one_person_course_data(PROFILE_NODE *profile)
{
 FILE *fp;
 char path[MAX_PATH + 1];
 COURSE_LIST_NODE *course_head;     /* COURSE_LIST_NODE is defined in shared_super_list.h */
 COURSE_LIST_NODE *ptr;
 
 /* sub_dir_name() is in shared_authenticate.c */
  snprintf(path, MAX_PATH + 1, "../%s/%c/%s/%s",
             USERS_DIR, sub_dir_name(profile->person.username), profile->person.username, COURSE_LIST_FNAME);
 
 fp = fopen(path, "r");
 if(!fp)
  {
    return; /* user has no courses */
  }
  
 get_shared_lock(fileno(fp), 1);        /* shared_lock.c */
 course_head = build_course_list(fp);   /*shared_super_list.c */
 release_lock(fileno(fp));              /*shared_lock.c */
 fclose(fp);
     
 for(ptr=course_head; ptr; ptr=ptr->next)
   add_one_course_data(profile, ptr);
 
 super_free_course_list(course_head);    /* shared_super_list.c */
}







static void 
free_master_list_person_lists()
{
  COURSE_NODE *master_ptr;
  USERNAME_GROUP_NODE *people_ptr;
  
  for(master_ptr = master_course_head; master_ptr; master_ptr=master_ptr->next)
   {
    while(master_ptr->user_head)
     {
      people_ptr = master_ptr->user_head;
      master_ptr->user_head = master_ptr->user_head->next;
      free(people_ptr);
     }
   }   

}



 
static 
PROFILE_NODE *add_full_result_data(PROFILE_NODE *profile_head)
{
  PROFILE_NODE *ptr;
    
  for(ptr = profile_head; ptr; ptr=ptr->next)
   {
    ptr -> course_head = (USER_COURSE_NODE *) 0;  /* make sure we start with no courses */
    add_one_person_course_data (ptr);
   }
   
  free_master_list_person_lists();   /* free up the individual person lists */ 
  return profile_head; 
}





     
 
static void free_master_course_list()
{
 COURSE_NODE *ptr;
 
 while(master_course_head)
  {
   ptr = master_course_head;
   master_course_head = master_course_head -> next;
   free(ptr);
  } 


} 

void set_user_course_list(PROFILE_NODE *ptr, int num, const char *escaped_realname, const char *key)
{
  #define MAX_TMP_NAME 50
  char name[MAX_TMP_NAME];
  char url[MAX_PATH +1];
  int i =0;
  USER_COURSE_NODE *cptr;

  for(cptr=ptr->course_head; cptr; cptr=cptr->next)
  {
      if(cptr->group != FACULTY)
      {     
         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.delete_url", num, i);  	        
         snprintf(url, MAX_PATH +1, "%s?id=%s&amp;crs=%s&amp;username=%s&amp;realname=%s", "super_delete_student",key,cptr->course_data->course_data.course_dir, ptr->person.username, escaped_realname);
         cs_set_value(name, url);
      }

         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.course_dir", num, i);  	        
         cs_set_value(name, cptr->course_data->course_data.course_dir);

         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.course_no", num, i);  	        
 	 cs_set_value( name,  cptr->course_data->course_data.course_no);
         
         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.is_temp", num, i);  	        
 	 cs_set_int_value(name, cptr->course_data->course_data.template); 
         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.semester", num, i);  	        
         cs_set_value(name, cptr->course_data->course_data.semester);
         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.access", num, i);  	        
         cs_set_int_value(name, cptr->course_data->course_data.access);
         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.title", num, i);  	        
         cs_set_value(name, cptr->course_data->course_data.title);
         snprintf(name, MAX_TMP_NAME, "user.%d.course.%d.instructor", num, i);  	        
         cs_set_value(name, cptr->course_data->course_data.instructor);

        i++; 

  }

  #undef MAX_TMP_NAME 
}




void
set_user_profile(PROFILE_NODE *head, const char *key)
{
  #define MAX_TMP_NAME 50
  PROFILE_NODE *ptr;
  int i =0; 
  char name[MAX_TMP_NAME];
  char url[MAX_PATH +1];
  char escaped_realname[MAX_NAME + 1];
  CONFIG_STRUCT dummy_conf;
  char bio_dir[MAX_PATH +1];

  for(ptr = head; ptr; ptr=ptr->next)
  {
     get_bio_dir("",&dummy_conf,ptr->person.username, bio_dir);    /* shared_bio.c */
     escape_realname(escaped_realname, ptr->person.realname);   /* shared_escape_realname.c */
     snprintf(name, MAX_TMP_NAME, "user.%d.username", i);
     cs_set_value(name, ptr->person.username);
     snprintf(name, MAX_TMP_NAME, "user.%d.realname", i);
     cs_set_value(name, ptr->person.realname);
     snprintf(name, MAX_TMP_NAME, "user.%d.id", i);
     cs_set_value(name, ptr->person.id);
     snprintf(name, MAX_TMP_NAME, "user.%d.bio_url", i);
     snprintf(url, MAX_PATH +1, "/%s/%s?id=%s&amp;user=%s&amp;admin=1", ALIAS,"bio_view", key, ptr->person.username);
     cs_set_value(name, url);
     if(bio_exists(bio_dir)) /* shared_bio.c */
     {
        snprintf(name, MAX_TMP_NAME, "user.%d.bio_exist", i);
        cs_set_int_value(name, 1);
     }
     snprintf(name, MAX_TMP_NAME, "user.%d.modify_url", i);
     snprintf(url, MAX_PATH +1, "%s?id=%s&amp;username=%s&amp;id_number=%s&amp;realname=%s", "super_modify_profile_form", key, ptr->person.username, ptr->person.id, escaped_realname);
     cs_set_value(name, url);

     snprintf(name, MAX_TMP_NAME, "user.%d.passwd_url", i);
     snprintf(url, MAX_PATH +1,  "%s?id=%s&amp;username=%s&amp;id_number=%s&amp;realname=%s", "super_reset_password",key, ptr->person.username, ptr->person.id, escaped_realname);
     cs_set_value(name, url);
          
     snprintf(name, MAX_TMP_NAME, "user.%d.log_url", i);
     snprintf(url, MAX_PATH +1, "%s?id=%s&amp;username=%s&amp;logfile=%s", "super_log_data", key, ptr->person.username, "all");
     cs_set_value(name, url);
     set_user_course_list(ptr, i, escaped_realname, key);
     i++;
  } 
  #undef MAX_TMP_NAME 
}

 
static
void set_full_results(const char *key, PROFILE_NODE *profile_head, int user_count, 
                                                  char *search, int field, int users, 
                                                  int sensitive, int where, int sort, int start_record, int records_per_page)
{
#define MAX_ALERT 200

   profile_head = add_full_result_data(profile_head);
   set_heading(user_count, search, field, users,FULL_RESULTS,  sensitive, where, sort, start_record, records_per_page, key);
   if(profile_head)
         set_user_profile(profile_head, key);
   free_master_course_list();

#undef MAX_ALERT
}   	           
 	           
 	           
 	           
 	  
 	  


     
static
void  set_search_results (const char *key,  char *search, int field, 
						int users, int results, int sensitive, int where, int sort,
			                          int start_record, int records_per_page)
{
 PROFILE_NODE *profile_head;
 int user_count;
 
     profile_head = build_profile_list(search, sensitive, where, field, users, sort,
                                          start_record, records_per_page, &user_count);  /* shared_search_profile.c */
     
     
     if(results == FULL_RESULTS)
     {
	 cs_set_int_value("full_record", 1);
         set_full_results(key, profile_head, user_count, search, field, users, sensitive, where, sort, start_record, records_per_page);
      } 
      else
        set_quick_list(key, profile_head, user_count, search, field, users, sensitive, where, sort, results,
                                           start_record, records_per_page);
             
     free_profile_list(profile_head);
} 




int
main()
{
  char search[MAX_PATH + 1];   /* from command line  - string to search for */
  int field;                   /* from command line - what fields to search on? */
  int users;                   /* from command line - what users to include? */
  int results;                 /* from command line - what form should results take */
  int sensitive;               /* from command line - case sensitive search? */
  int where;                   /* from command line - match must contain, start with, end with? */
  int sort;                    /* from command line - sort by? */
  int start_record;            /* from command line - start record */
  int records_per_page;        /* from command line - records per page? */
    
  char key[MAX_KEY +1];
  /* dummy variables */
  char crs[MAX_PATH +1];
  char group[MAX_ID +1];
  char oper[20];

  SESSION user;

  cs_cgi_init();
  read_search_parameters(key, crs, group, oper, search, &field, 
                                   &users, &results,  &sensitive, &where, &sort, &start_record, &records_per_page); /*shared_search_profile.c */
    validate_super_key(key, &user);
    set_admin_page(&user, key, 0, "super_info_form");  /* shared_super_menu.c */

    set_search_results (key, search, field, users, results, sensitive, where, sort, start_record, records_per_page);
    cs_cgi_display("super_info", 1);
    cs_cgi_destroy(); 
    return 0;

}
