#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_person_list.h"
#include "manhat-lib/shared_teamstring.h"

#define MAX_NAME_LIST 25	/* store this many names in the list of team members * */



typedef struct team_node
{
  char team;
  int total_msgs;
  int total_unread;
  int total_flagged;
  struct team_node *next;
  char realname[MAX_NAME_LIST][MAX_NAME + 1];
  int name_overflow;					  /** are there more than MAX_NAME_LIST members in this team **/
  int total_members;                                      /** how many people are on this team? */
}
TEAM_NODE;





static void
read_parameters (char *course, char *key)
{

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



static void
set_main_menu_url (char *course, char *key)
{
  char url[MAX_PATH +1];

  snprintf (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s","main_menu", course, key);
  cs_set_value("main_menu_url", url);

}








void
update_existing_team (char team, char *realname, TEAM_NODE *team_head)
{

  TEAM_NODE *ptr;

  for (ptr = team_head; ptr && (ptr->team != team); ptr = ptr->next);
  if (!ptr)
    cs_critical_error (ERR_TEAM_NOT_FOUND, "");

  ptr ->total_members++;
  if(ptr->total_members >= MAX_NAME_LIST)
      ptr->name_overflow = 1;
  else
	strncpy (ptr->realname[ptr->total_members - 1], realname, MAX_NAME + 1);

}



TEAM_NODE *
add_new_team (char team, char *realname, TEAM_NODE *team_head)
{

  TEAM_NODE *ptr;
  int i;

  if (!team_head)
    {
      team_head = (TEAM_NODE *) malloc (sizeof (TEAM_NODE));
      if (!team_head)
	cs_critical_error (ERR_MALLOC_FAILED, "");
      ptr = team_head;
    }
  else
    {
      for (ptr = team_head; ptr->next; ptr = ptr->next);
      ptr->next = (TEAM_NODE *) malloc (sizeof (TEAM_NODE));
      if (!ptr->next)
	cs_critical_error (ERR_MALLOC_FAILED, "");
      ptr = ptr->next;
    }

  ptr->team = team;
  ptr->next = 0;
  ptr->total_msgs = 0;
  ptr->total_unread = 0;
  ptr->total_flagged = 0;
  ptr->name_overflow = 0;
  ptr -> total_members = *realname? 1: 0;
  strncpy (ptr->realname[0], realname, MAX_NAME + 1);
  for (i = 1; i < MAX_NAME_LIST; i++)
    *(ptr->realname[i]) = '\0';

  return team_head;
}




TEAM_NODE *
add_team_nodes (CONFIG_STRUCT *conf, SESSION *user)
{
    P_NODE *p_head, *ptr;
    TEAM_NODE *team_head = 0;
    TEAM_NODE *t_ptr;
    int team_listed;
    
    p_head = build_option_person_list(conf); /* shared_person_list.c */

    for(ptr=p_head; ptr; ptr=ptr->next)
    {
       for(t_ptr = team_head, team_listed=0; t_ptr && !team_listed; t_ptr=t_ptr->next)
          team_listed = (t_ptr->team == ptr->data.team);
       if (!team_listed)
	  team_head = add_new_team (ptr->data.team, ptr->data.realname, team_head);
        else
	  update_existing_team (ptr->data.team, ptr->data.realname, team_head);
    }
  free_option_person_list (p_head);   /* shared_person_list.c */
  return team_head;
}





static 
TEAM_NODE *update_team_count (char team, int msg_count, int unread_count, int flagged_count, TEAM_NODE *team_head)
{

  TEAM_NODE *ptr;
  
  for (ptr = team_head; ptr && (ptr->team != team); ptr = ptr->next);
  if (!ptr)  /*team has no current members */
   {
    team_head = add_new_team(team, "", team_head);   /* add the team */
    for (ptr = team_head; ptr && (ptr->team != team); ptr = ptr->next);  /* find this team again */
   } 
    

  if(ptr)    /* this MUST be the case! */
    {
      ptr->total_msgs+=msg_count;
      ptr->total_unread += unread_count;
      ptr->total_flagged += flagged_count;
    }

 return team_head;
}







TEAM_NODE *
build_team_list (CONFIG_STRUCT *conf, SESSION *user)
{

  MSG_TREE_NODE *ptr;
  int msg_count;
  int unread_count;
  int flagged_count;
  TEAM_NODE *team_head;
  time_t current_time;  /* needed for call to build_msg_tree */
  

  team_head = add_team_nodes (conf, user);

  /* in next 1-> show_all_team_teach, 0 = don't show teacher hidden */
  build_msg_tree(user, TEAM_TEACH, 1, 0, &current_time);    /* shared_news_util.c */

  for(ptr=tree_head; ptr; ptr=ptr->next)   /* for each topic in the tree */
  {
   count_topic_msgs(ptr, &msg_count, &unread_count, &flagged_count);   /* shared_news_util.c */
   team_head = update_team_count (ptr->data.info.sender_team, msg_count, unread_count, flagged_count, team_head);
  } 
   
   free_msg_tree(tree_head);   /* shared_news_util.c */
   return team_head;
}



static void
free_team_list (TEAM_NODE *team_head)
{
  TEAM_NODE *ptr;

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




static int
record_cmp (TEAM_NODE * a, TEAM_NODE * b)
{
  if ((a->team) < (b->team))
    return -1;
  if ((a->team) > (b->team))
    return 1;
  return 0;
}




static
TEAM_NODE *sort_team_list (TEAM_NODE *team_head)
{
  TEAM_NODE *q, *tail, *p, *r;
  if (team_head != NULL)
    {
      tail = team_head;
      while (tail->next)
	{
	  q = tail->next;
	  if (record_cmp (q, team_head) < 0)
	    {
	      tail->next = q->next;
	      q->next = team_head;
	      team_head = q;
	    }
	  else
	    {
	      r = team_head;
	      p = r->next;
	      while (record_cmp (q, p) > 0)
		{
		  r = p;
		  p = r->next;
		}
	      if (q == p)
		tail = q;
	      else
		{
		  tail->next = q->next;
		  q->next = p;
		  r->next = q;
		}
	    }
	}
    }
 return team_head;   
}



void
set_team_data (char *course, char *key, CONFIG_STRUCT *conf, SESSION *user)
{
 #define MAX_TMP_NAME 30
 
  TEAM_NODE *ptr;
  int i;
  int team_number = 0;
  TEAM_NODE *team_head;
  char name[MAX_TMP_NAME + 1];
  char teamstring[20];
  team_head = build_team_list (conf, user);
  team_head = sort_team_list(team_head); 
  
  if (team_head)
    {
      for (team_number=0, ptr = team_head; ptr; ptr = ptr->next, team_number++)
	{
          snprintf(name, MAX_TMP_NAME, "team.%d.total_members",team_number);
	  cs_set_int_value(name, ptr->total_members);	
	  
          snprintf(name, MAX_TMP_NAME, "team.%d.total_msgs",team_number);
	  cs_set_int_value(name, ptr->total_msgs);	


	  snprintf(name, MAX_TMP_NAME, "team.%d.total_unread",team_number);
	  cs_set_int_value(name, ptr->total_unread);


	  snprintf(name, MAX_TMP_NAME, "team.%d.total_flagged",team_number);
	  cs_set_int_value(name, ptr->total_flagged);

	  snprintf(name, MAX_TMP_NAME, "team.%d.is_partial_member_list",team_number);
	  cs_set_int_value(name, ptr->name_overflow);

          
          snprintf(name, MAX_TMP_NAME, "team.%d.team_name",team_number);
          
          get_team_name(ptr->team, teamstring);   /* shared_teamstring.c */
	  cs_set_value(name, teamstring);
	  
	  
	  snprintf(name, MAX_TMP_NAME, "team.%d.team_letter",team_number);
	  snprintf(teamstring,3, "%c", ptr->team);
	  cs_set_value(name, teamstring);

	  for (i = 0;  (i < MAX_NAME_LIST) && strlen (ptr->realname[i]); i++)
	   {
             snprintf(name, MAX_TMP_NAME, "team.%d.member.%d", team_number, i);
	     cs_set_value(name, ptr->realname[i]);
	   }
	}

      free_team_list (team_head);
    }
 #undef MAX_TMP_NAME 
}






static void
set_team_list (char *course, char *key, CONFIG_STRUCT *conf, SESSION *user)
{

  cs_set_value("crs", course);
  cs_set_value("id", key);


  cs_set_course_info(conf);
  cs_set_current_time();

  set_main_menu_url (course, key);
  set_team_data (course, key, conf, user);

}





int
main (void)
{
  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 */


  cs_cgi_init();
  read_parameters (course, key);
  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, "");
    
  set_discussion_names (conf.course_path, user.username, TEAM_TEACH);	/* shared_news_util.c */

  set_team_list (course, key, &conf, &user);

  cs_cgi_display("news_team_list", 1);
  cs_cgi_destroy();
  return 0;
}


