#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>		/* for tolower() */


#include "global.h"
#include "custom.h"		/* for date FORMAT strings */

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_msg_line.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_translate_url.h"
#include "manhat-lib/shared_access.h"
#include "manhat-lib/shared_bio.h"



SESSION user;
CONFIG_STRUCT conf;

ATTACHMENT_NODE *attachment_head = 0;	/* linked list of file info */



static void
read_parameters (char *course, char *key, long *offset,
		 char *from_prog, char *student, int *del_link,
		  int *printer_friendly, int *fixed_font)
{

  char off_set[MAX_FILENAME + 1];	/* for holding the long value, length should
					   be long enough, don't you think? */

  cs_get_required_parameter ("crs", course, MAX_PATH);
  cs_get_required_parameter ("id", key, MAX_KEY);

  cs_get_required_parameter ("loc", off_set, MAX_FILENAME);
  *offset = atol (off_set);

  cs_get_optional_parameter ("from", from_prog, MAX_PATH);
  
  cs_get_optional_parameter ("student", student, MAX_USERNAME);
  cs_get_optional_parameter ("del_link", off_set, 5);
  *del_link = strlen(off_set);
  
    /* provide printer-friendly version? */
  cs_get_optional_parameter ("print", off_set, 5);              /* shared_cs_util.c */
  *printer_friendly = *off_set? 1: 0;


    /* provide preformatted text (instead of proportional) ? */
  cs_get_optional_parameter ("fixed", off_set, 5);              /* shared_cs_util.c */
  *fixed_font = *off_set? (atoi(off_set)? 1 : 0) : 0;

}



MSG_TREE_NODE *find_last_node(MSG_TREE_NODE *root)
{
 MSG_TREE_NODE *ptr;

 ptr = root;
 
 for(;;)
 {
  for(;ptr->next;ptr=ptr->next);
  if(!ptr->reply)
      return ptr;
  ptr=ptr->reply;
 }
}   





static 
void get_previous_msg_offset(MSG_TREE_NODE *msg_ptr,  long *offset)
{
MSG_TREE_NODE *leaf;

  if(msg_ptr->data.info.reply_to == -1)  /* msg is the topic */
    *offset = -1;
 else
  if( (msg_ptr->prev->reply == msg_ptr) ||    /* msg was first reply to another msg */
      (!msg_ptr->prev->reply))                /* prev. message had no replies */
    *offset = msg_ptr->prev->offset;
 else
 {
   leaf = find_last_node(msg_ptr->prev->reply);
   *offset = leaf->offset;
 }
}   



static 
void get_next_msg_offset(MSG_TREE_NODE *msg_ptr,  long *offset)
{
 MSG_TREE_NODE *ptr,*last;
 int done;

 if(msg_ptr->data.info.reply_to == -1)  /* msg is the topic */
    *offset = msg_ptr->reply? msg_ptr->reply->offset: - 1;
 else
  if(msg_ptr->reply)
        *offset = msg_ptr->reply->offset;
 else
   if(msg_ptr->next)
          *offset = msg_ptr->next->offset;
 /* message is a leaf */
 else
 {
  for(ptr = msg_ptr->prev, last = msg_ptr, done = 0; !done;  last=ptr, ptr=ptr->prev)
   {
    done = (ptr->data.info.reply_to == -1) ||
           ((ptr->reply == last) && (ptr->next));
   if(done) break;        
   }        
   
  if(ptr->data.info.reply_to == -1)
     *offset = -1;
  else
     *offset = ptr->next->offset;   

 }
}   



static void
get_offsets (MSG_TREE_NODE *msg_ptr,  long *next_msg_offset, long *prev_msg_offset)
	     
{

 get_previous_msg_offset(msg_ptr,prev_msg_offset);
 get_next_msg_offset(msg_ptr,  next_msg_offset);

}      





static void
set_command_urls (MSG_TREE_NODE *msg_ptr, MSG_TREE_NODE *topic_ptr,
                          char *course, char *key, char *from,  char *fac_username, char *student, int can_write)
{

#define LONG_STRING 512
  long next_offset, prev_offset;
  char temp[LONG_STRING + 1];

  /*** back button *****/
  translate_url_substitutes (temp, from, LONG_STRING + 1, 1);	/* shared_translate_url.c */
  cs_set_value("back_button_url", temp);

  /*  Main menu */
  snprintf (temp, LONG_STRING +1, "%s?crs=%s&amp;id=%s", "main_menu", course, key);
  cs_set_value("main_menu_url", temp);
  
  /****  Back to Topic Index */
  snprintf (temp, LONG_STRING +1, "%s?crs=%s&amp;id=%s&amp;grp=%d", "news_topic", course, key, ASSIGNMENTS );
  cs_set_value("news_topic_url", temp);

  /* Data for 'Reply' button */
  if ( (msg_ptr == topic_ptr) || !can_write)
     cs_set_value("reply_url", "");
  else
    {
       snprintf(temp, LONG_STRING +1, "%s?crs=%s&amp;id=%s&amp;grp=%d&amp;topic=%d&amp;loc=%ld&amp;reply_to=%d&amp;to=%s&amp;from=%s",
       			"news_new_memo", course, key, ASSIGNMENTS, msg_ptr->data.info.topic_id, 
       			msg_ptr->offset, msg_ptr->data.info.msg_id,student,from);
       cs_set_value("reply_url", temp);
    }
    

  /* find next, previous messages */
  get_offsets (msg_ptr,  &next_offset, &prev_offset);

  /**** data for read next msg****/
  if (next_offset != -1)
  {
    snprintf(temp, LONG_STRING +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;student=%s&amp;from=%s",
    					"assign_read", course, key, next_offset, student, from);
    cs_set_value("next_msg_url", temp);
  }

  /* data for read previous msg */
  if (prev_offset != -1)
  {
    snprintf
      (temp, LONG_STRING +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;student=%s&amp;from=%s",
       					"assign_read", course, key, prev_offset, student, from);
    cs_set_value("prev_msg_url", temp);
  }


  snprintf
    (temp, LONG_STRING +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;grp=%d","news_info", course, key, msg_ptr->offset, ASSIGNMENTS);
  cs_set_value("info_url", temp);




/** set flag value and url */

   cs_set_int_value("flagged", msg_ptr->user_data.flagged? 1:0);

   snprintf(temp, 
       LONG_STRING + 1, "%s?crs=%s&amp;id=%s&amp;grp=%d&amp;msg_id=%d&amp;from=assign_read%ccrs%c%s%cid%c%s%cloc%c%ld%cstudent%c%s&amp;from_from=%s",
        "news_flag", course, key, ASSIGNMENTS, msg_ptr->data.info.msg_id, 
        QMARK_SUB, 
        EQUAL_SUB,
        course,
        AMP_SUB,
        EQUAL_SUB,
        key,
        AMP_SUB,
        EQUAL_SUB,
        msg_ptr->offset,
        AMP_SUB,
        EQUAL_SUB,
        student,
        from);
   cs_set_value("flag_url", temp);  



#undef LONG_STRING
}





static void
process_msg_node (MSG_TREE_NODE *msg_ptr, int *website_attached, CONFIG_STRUCT *conf, 
										SESSION *user)
{
  FILE *fp;
  int fd;
  
  char infopath[MAX_PATH + 1];
  int i;
  NEWS_INFO infofile_info;
  ATTACHMENT_NODE *aptr = 0;

  if(!msg_ptr->user_data.time_read && (conf->access != ACCESS_CAPTURE))   /* if msg is unread and not in capture mode */
   {
       mark_msg_as_read(&(msg_ptr->data),conf,user);   /*shared_news_util.c */
   }    



  /*** if there are attachments, read the info file to 
  **** build the attachment list
  ***/

 *website_attached = 0;  /* assume this to start */
 if(msg_ptr->data.info.attachments)
 {
   snprintf(infopath,MAX_PATH + 1,"%s%s/%s/%s/%s",conf->course_path,PEOPLE_DIR,
                            msg_ptr->data.info.sender,discussion_fname,msg_ptr->data.info_fname);
  
  fp = fopen(infopath,"r");
  if(!fp)
     cs_critical_error (ERR_FOPEN_READ_FAILED, infopath);

  fd = fileno(fp);   
  get_shared_lock(fd, 1);                      /* shared_lock.c */    

  if(fread( &infofile_info, sizeof(NEWS_INFO), 1, fp) != 1)
   cs_critical_error (ERR_FREAD_FAILED, infopath); 


  /* process attachments, build linked list */
  *website_attached = (infofile_info.attachments == -1);
     
  if (*website_attached)
    infofile_info.attachments = 1;	/* since we have to pick up the dirname */

  for (i = 1; i <= infofile_info.attachments; i++)
    {
      if (!attachment_head)
	{
	  attachment_head =
	    (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!attachment_head)
	    cs_critical_error (ERR_MALLOC_FAILED, infopath);
	  aptr = attachment_head;
	}
      else
	{
	  aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!aptr->next)
	    cs_critical_error (ERR_MALLOC_FAILED, infopath);
	  aptr = aptr->next;
	}

      if (fread(&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1)
	 cs_critical_error (ERR_FREAD_FAILED, infopath); 
      aptr->next = 0;
    }				/* for .. */

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




static void
free_attachment_list ()
{
  ATTACHMENT_NODE *aptr;

  while (attachment_head)
    {
      aptr = attachment_head;
      attachment_head = attachment_head->next;
      free (aptr);
    }
}







static void
set_news_msg_values (char *course, char *key,
		  long offset, char *from, char *student,
	           CONFIG_STRUCT *conf, SESSION *user, int can_write)
{
 MSG_TREE_NODE *msg_ptr;
 MSG_TREE_NODE *topic_ptr;
 int website_attached;
 int msg_count;
 time_t current_time;
 int teacher_hidden;
 int read_only;
 char msg_path[MAX_PATH + 1];
 char url[MAX_PATH + 1]; 
  
 build_fac_assign_read_tree(user,  offset, student, &msg_ptr, &topic_ptr, &msg_count, &current_time); /* shared_news_util.c */

 if(!msg_ptr || !tree_head)
   cs_critical_error(ERR_CANT_FIND_THIS_OFFSET, "set_news_msg_values()");


 /* an empty 'from' string indicates that we need to return to the "assign_fac_expand"
 * program
 */

 if (!strlen (from))
    snprintf (from, MAX_PATH + 1, "%s%ccrs%c%s%cid%c%s%ctopic%c%d%cloc%c%ld",
	      "assign_fac_expand", QMARK_SUB,EQUAL_SUB,course,
	      AMP_SUB, EQUAL_SUB,key,AMP_SUB, EQUAL_SUB, 
	      msg_ptr->data.info.topic_id,AMP_SUB, EQUAL_SUB, topic_ptr->offset);



 cs_set_value("from", from);
 
 teacher_hidden = is_teacher_hidden (topic_ptr->data.status, topic_ptr->data.release_time,   /* shared_news_util.c */
                                        topic_ptr->data.unrelease_time, current_time);
                                      
 read_only = BASIC_STATUS(topic_ptr->data.status) == READ_ONLY ? 1 : 0;  /* see global.h */                                       


 process_msg_node (msg_ptr, &website_attached, conf, user);


 /* shared_news_util.c */
 set_assign_read_heading_data (msg_ptr,  "msg.", topic_ptr,  course,  key,       
	                                    conf, teacher_hidden, can_write, read_only);

 set_command_urls (msg_ptr, topic_ptr, course, key,  from, user->username, student, can_write);

 cs_set_bio_link( msg_ptr->data.info.sender,course, conf, key, ASSIGNMENTS, 0, "user", 30);  /* shared_bio.c */

 /* shared_news_util.c */
 set_news_attachment_data (msg_ptr, 
                         topic_ptr->data.info.subject, 
                         course, 
                         key, 
                         ASSIGNMENTS,  
                         website_attached,
                         "assign_read", 
                         user->team,    /* but it doesn't really matter */
                         0,             /* is_fac_teamteach */
                         student,
                         conf, 
                         0, 
			 user->username,  
			 attachment_head, 
			 "");          /* name prefix is blank */



 snprintf (msg_path, MAX_PATH + 1, "%s%s/%s/%s/%s",
	    conf->course_path, PEOPLE_DIR, msg_ptr->data.info.sender, discussion_fname, msg_ptr->data.info.msg_fname);


 set_msg_body_data(msg_path, "", "");   /* shared_msg_line.c */




 /*** The teacher can delete an assignment if no one has yet submitted
 **** work for the assignment.  The teacher can delete other messages
 **** sent TO students at any time. (this allows him/her to retrieve
 **** feedback sent to the wrong student.  Messages sent by the student
 **** to the teacher cannot be deleted
 ***/

      if ( (msg_count < 2) || ((msg_ptr->data.info.reply_to != -1) && 
                                     strcmp(msg_ptr->data.info.sender, msg_ptr->data.info.receiver_username)))
          {
                
        	if(can_write)
        	  {
        	    cs_set_value("insert_kill_form", "1");
        	  }
         } 

      if(website_attached)
      {
         snprintf(url, MAX_PATH + 1, "%s?crs=%s&amp;id=%s&amp;sender=%s&amp;dir=%s&amp;grp=%d",
             "web_page_zip", course, key, msg_ptr->data.info.sender, 
              attachment_head->data.unique_fname, ASSIGNMENTS);		
         cs_set_value("website_zip_download_url", url);   /* shared_cs_util.h */
         
         cs_set_value("website_dirname", attachment_head->data.unique_fname); /* shared_cs_util.h */
              
      }
         
         


  free_msg_tree(tree_head); /*shared_news_util.c */
  free_attachment_list ();
}







int
main (void)
{
  char course[MAX_PATH + 1];			/* from crs=? command line */
  char key[MAX_KEY + 1];			/* from id=? command line */
  long offset;					/* from loc=? command line */
  char from_prog[MAX_PATH + 1];			/* from from=? command line */
  char student_username[MAX_USERNAME + 1];	/* optional command line */
  int can_write;
  int del_link;					/* from del_link=?command line  do we need to rm a symbolic link
				   		** to an attached web page?   
				   		*/

  int printer_friendly;         /* from print=? command line  provide "printer friendly" version? */				 
  int fixed_font;               /* from fixed=? command line  print body as fixed font? */				 


  cs_cgi_init();                 		/* shared_cs_util.c */
  read_parameters (course, key, &offset,  from_prog, student_username, &del_link, &printer_friendly, &fixed_font);
  read_configuration_file (course, &conf);	/* shared_util.c */
  validate_key (key, &user, &conf);		/* shared_util.c */

  
  
  if (user.group != FACULTY)
       cs_critical_error (ERR_REQUEST_DENIED, "");    /* shared_cs_util.c */

  cs_set_value("is_faculty","1");   
  
  if(conf.access == ACCESS_CAPTURE)
      cs_set_value("capture_mode", "1");        /* shared_cs_util.h */

   cs_set_int_value("printer_friendly", printer_friendly);
   cs_set_int_value("fixed_font", fixed_font);


  can_write = has_write_permission(&user, &conf);	/* shared_access.c */
  if(can_write)
      cs_set_value("can_write", "1");
  
  cs_set_course_info(&conf);     /* shared_cs_util.c */
  

  
  cs_set_value("crs", course);    		/* shared_cs_util.h */
  cs_set_int_value("grp", ASSIGNMENTS);         /* shared_cs_util.c */
  cs_set_value("key", key);	  		/* shared_cs_util.h */
  cs_set_value("username",user.username);  	/* shared_cs_util.h */
  if(*student_username)
     cs_set_value("student_username", student_username);
     
  set_discussion_names (conf.course_path, user.username, ASSIGNMENTS);	/* shared_news_util.c */

  set_news_msg_values (course, key, offset, from_prog, student_username, &conf, &user, can_write);

  if (del_link)
    remove_stale_symlinks (user.username, course, conf.access); /*shared_news_util.c */



  /* NOTE: this program uses the same lang file as news_read.c **/
  cs_load_lang("news_read");

  cs_cgi_display("assign_read", 1);    /* shared_cs_util.c */


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




