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

#include "global.h"

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_translate_url.h"

#define NOTEAM '!'		/* flags no team parameter defined */
typedef struct expanded_topic_node
{
  int topic;
  struct expanded_topic_node *next;
}
EXPANDED_TOPIC_NODE;



EXPANDED_TOPIC_NODE *expanded_head = 0;	/* list of topics that are expanded */


static void
read_parameters (char *course,
		 char *key, int *grp, int *topic, int *expand, char *from)
{
  char tmp[10];



  cs_get_required_parameter ("crs", course, MAX_PATH);
  cs_get_required_parameter ("id", key, MAX_KEY);
  cs_get_required_parameter ("grp", tmp, 5);
  *grp = atoi (tmp);

  cs_get_required_parameter ("topic", tmp, 5);
  *topic = atoi (tmp);

  cs_get_required_parameter ("expand", tmp, 5);
  *expand = atoi (tmp);

  cs_get_required_parameter ("from", from, MAX_PATH);



}

static void
report_write_error ()
{
  cs_critical_error (ERR_ERROR_WRITING_FILTER, "");
}

static void
report_memory_error ()
{
  cs_critical_error (ERR_MALLOC_FAILED,"");
}

static void
add_to_list (int new_topic)
{
  EXPANDED_TOPIC_NODE *ptr;

  if (!expanded_head)
    {
      expanded_head =
	(EXPANDED_TOPIC_NODE *) malloc (sizeof (EXPANDED_TOPIC_NODE));
      if (!expanded_head)
	report_memory_error ();
      expanded_head->topic = new_topic;
      expanded_head->next = (EXPANDED_TOPIC_NODE *) 0;
    }
  else
    {
      for (ptr = expanded_head; ptr->next; ptr = ptr->next)
	if (ptr->topic == new_topic)
	  return;		/* new_topic is already on the list */

      if (ptr->topic == new_topic)
	return;			/* check last node */

      ptr->next =
	(EXPANDED_TOPIC_NODE *) malloc (sizeof (EXPANDED_TOPIC_NODE));
      if (!ptr->next)
	report_memory_error ();
      ptr = ptr->next;
      ptr->topic = new_topic;
      ptr->next = (EXPANDED_TOPIC_NODE *) 0;
    }
}

static void
remove_from_list (int remove_topic)
{
  EXPANDED_TOPIC_NODE *ptr, *ptr2;

  for (ptr = expanded_head; ptr && (ptr->topic != remove_topic);
       ptr = ptr->next);

  if (!ptr)
    return;			/* not found, shouldn't happen, but let's ignore */
  if (ptr == expanded_head)
    {
      expanded_head = expanded_head->next;
      free (ptr);
    }
  else
    {
      for (ptr2 = expanded_head; ptr2 && (ptr2->next != ptr);
	   ptr2 = ptr2->next);

      if (!ptr2)
	cs_critical_error (ERR_REMOVAL_FROM_LIST_FAILED, "");

      ptr2->next = ptr->next;
      free (ptr);
    }
}

static void
build_expand_list (const char *filter_path, NEWS_FILTER * filter)
{
  FILE *fp;
  EXPANDED_TOPIC_NODE *ptr = 0;
  int topic;

  fp = fopen (filter_path, "r");
  if (fp)
    {
      fread (filter, sizeof (NEWS_FILTER), 1, fp);
      while (fread (&topic, sizeof (int), 1, fp) == 1)
	{
	  if (!expanded_head)
	    {
	      expanded_head =
		(EXPANDED_TOPIC_NODE *) malloc (sizeof (EXPANDED_TOPIC_NODE));
	      ptr = expanded_head;
	    }
	  else
	    {
	      ptr->next =
		(EXPANDED_TOPIC_NODE *) malloc (sizeof (EXPANDED_TOPIC_NODE));
	      ptr = ptr->next;
	    }
	  if (!ptr)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  ptr->topic = topic;
	  ptr->next = (EXPANDED_TOPIC_NODE *) 0;
	}

      fclose (fp);
    }
}


static void
write_expand_list (const char *filter_path, NEWS_FILTER * filter)
{
  FILE *fp;
  EXPANDED_TOPIC_NODE *ptr;

  fp = fopen (filter_path, "w");
  if (!fp)
    report_write_error ();
  if (fwrite (filter, sizeof (NEWS_FILTER), 1, fp) != 1)
    report_write_error ();
  for (ptr = expanded_head; ptr; ptr = ptr->next)
    if (fwrite (&ptr->topic, sizeof (int), 1, fp) != 1)
      report_write_error ();
  fclose (fp);
}


static void
free_expand_list ()
{
  EXPANDED_TOPIC_NODE *ptr;

  while (expanded_head)
    {
      ptr = expanded_head;
      expanded_head = expanded_head->next;
      free (ptr);
    }
}


static void
expand_topic (int expand, int new_topic)
{
  NEWS_FILTER filter;
  char filter_path[MAX_PATH + 1];

  snprintf (filter_path, MAX_PATH + 1, "%s/%s", discussion_path,
	    NEWS_FILTER_FNAME);

  build_expand_list (filter_path, &filter);


  if (expand)			/* if we are adding 'new_topic' */
    add_to_list (new_topic);
  else
    remove_from_list (new_topic);



  write_expand_list (filter_path, &filter);
  free_expand_list ();
}





static void
redirect_user (char *from, int topic)
{
  char new_from[MAX_PATH + 1];

  translate_url_substitutes (new_from, from, MAX_PATH + 1, 0);	/* shared_translate_url.c */
  if(topic == -1)
    printf ("Location: %s\n\n", new_from);
  else
    printf ("Location: %s#%d\n\n", new_from,topic);
}




static void
expand_all (SESSION *user, int grp)
{
  FILE *fp;
  NEWS_FILTER filter;
  char filter_path[MAX_PATH + 1];
  MSG_TREE_NODE *ptr;
  
  snprintf (filter_path, MAX_PATH + 1, "%s/%s", discussion_path,
	    NEWS_FILTER_FNAME);

  fp = fopen (filter_path, "r");
  if (fp)
    {
      if (fread (&filter, sizeof (NEWS_FILTER), 1, fp) != 1)
	cs_critical_error (ERR_ERROR_READING_FILTER, "");
      fclose (fp);
    }
  else
  {
    filter.oldest_first = 1;
    filter.show_user_hidden = 1;
    filter.show_teacher_hidden = 1;
  }   

  fp = fopen (filter_path, "w");
  if (!fp)
    cs_critical_error (ERR_ERROR_CREATING_FILTER, "");
  if (fwrite (&filter, sizeof (NEWS_FILTER), 1, fp) != 1)
    cs_critical_error (ERR_ERROR_WRITING_FILTER, "");

  build_topic_only_tree(user,grp); /* shared_news_util.c */

  for(ptr = tree_head; ptr; ptr=ptr->next)
    if (fwrite (&ptr->data.info.topic_id, sizeof (int), 1, fp) != 1)
      cs_critical_error (ERR_ERROR_WRITING_FILTER, "");
  fclose (fp);
  free_msg_tree(tree_head);  /* shared_news_util.c */
}


static void
collapse_all ()
{
  FILE *fp;
  NEWS_FILTER filter;
  char filter_path[MAX_PATH + 1];

  snprintf (filter_path, MAX_PATH + 1, "%s/%s",
	    discussion_path, NEWS_FILTER_FNAME);

  fp = fopen (filter_path, "r");
  if (fp)
    {
      if (fread (&filter, sizeof (NEWS_FILTER), 1, fp) != 1)
	cs_critical_error (ERR_ERROR_READING_FILTER, "");
      fclose (fp);
    }
  else
   {
    filter.oldest_first = 1;
    filter.show_user_hidden = 1;
    filter.show_teacher_hidden = 1;
   }
    
  fp = fopen (filter_path, "w");
  if (!fp)
    cs_critical_error (ERR_ERROR_CREATING_FILTER, "");
  if (fwrite (&filter, sizeof (NEWS_FILTER), 1, fp) != 1)
    cs_critical_error (ERR_ERROR_WRITING_FILTER, "");
  fclose (fp);
}



int
main (void)
{
  char course[MAX_PATH + 1];	/* from crs=? command line */
  char key[MAX_KEY + 1];	/* from id=? command line */
  int grp;			/* from grp=? command line */
  int topic;			/* from topic=? command line */
  int expand;			/* from expand=? command line */
  char from[MAX_PATH + 1];	/* from from=? command line */
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */
  char scratch[10];

  cs_cgi_init();

  read_parameters (course, key, &grp, &topic, &expand, from);
  read_configuration_file (course, &conf);	/* shared_util.c */
  validate_key (key, &user, &conf);	/* shared_util.c */

  set_discussion_names (conf.course_path, user.username, grp);	/* shared_news_util.c */
  if (topic == -1)
    {
      
      if (expand)
       {
         if ((user.group == FACULTY) && (grp == TEAM_TEACH))
          {
             cs_get_required_parameter ("team", scratch, 5);	/* shared_cgi_util.c */
             user.team =  *scratch;   /* switch this teacher's team to that supplied on the command line */
           }
 
	expand_all (&user,grp);
       }
      else
	collapse_all ();
    }
  else
    expand_topic (expand, topic);

  redirect_user (from, topic);
  cs_cgi_destroy();
  return 0;

}



