#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>

#include "../global.h"
#include <ClearSilver.h>

#include "shared_util.h"   /* file_exists() */
#include "shared_authenticate.h"
#include "shared_user_index.h"
#include "shared_add_util.h"
#include "shared_lock.h"
#include "shared_central_user.h"
#include "shared_strtrm.h" /* for strtrm() */
#include "shared_file_util.h"  /* for file_exists() */
#include "shared_encrypt.h"
#include "shared_access.h"
#include "shared_cs_util.h"

#define UNKNOWN_USER_PREF_VALUE "?"


HDF *global_user_prefs = 0;


static void get_user_prefs_path(const char *username, char *path)
{
   char dir;


   dir = sub_dir_name(username);   /* shared_authenticate.c */
   snprintf(path, MAX_PATH + 1,
              "../%s/%c/%s/%s", USERS_DIR, dir, username,USER_PREFS_FNAME);
}
 



void free_user_prefs()
{

 if(global_user_prefs)
   {
     hdf_destroy(&global_user_prefs);
     global_user_prefs = (HDF *) 0;
   }
}




void store_user_prefs( const char *username)
{
 char path[MAX_PATH + 1];
 
 if(global_user_prefs)
  {
    get_user_prefs_path(username, path);
    hdf_write_file(global_user_prefs, path);
    free_user_prefs();
  }
 else
   {
     cs_critical_error(ERR_GENERAL_ERROR,"global_user_prefs not defined");
   } 
}




/** Prior to version 3.3, a text file named 'id' (#defined as ID_FNAME in global.h) was
*** used to store a user's real name and id number.
***
*** This file had two lines.  The first was the id number, and the second
*** was the person's real name.
***
*** Starting with 3.3, this file  replaced with a ClearSilver hdf file named prefs.hdf 
*** (#defined as USER_PREFS_FNAME in global.h) that stores the person's real name, id number
*** plus whatever other name/value pairs we'd like to use in the future.
***
*** This function converts the old 'id' file to the new 'prefs.hdf' format.  It will only be 
*** called to ONCE for each user to convert the old format to the new format.
**/


static void convert_old_id_file(const char *username)
{
 FILE *fp;
 char line[200];
 char id_fname[MAX_PATH + 1];
 char dir;
 char realname[MAX_NAME + 1];
 char id[MAX_ID + 1];
  
 
  dir = sub_dir_name(username);  /* shared_authenticate.c */
 
 
  snprintf(id_fname, MAX_PATH + 1,
              "../%s/%c/%s/%s", USERS_DIR, dir, username,ID_FNAME);


 fp = fopen(id_fname,"r");
 if(!fp)
     return;   /* let the calling function decide what to do */
     
     
 /* line 1 is the id number */
 if(!fgets(line,200,fp))
  {
   fclose(fp);
   return;
  } 
  strtrm(line);   /* shared_strtrm.c */
  strncpy(id, line, MAX_ID + 1);
  *(id + MAX_ID) = '\0';


  /* line 2 is the real name */ 
  if(!fgets(line,200,fp))
   {
      fclose(fp);
      return;
   }   
  strtrm(line);   /*shared_strtrm.c */
  strncpy(realname,line,MAX_NAME + 1);
  *(realname + MAX_NAME) = '\0';
  
  fclose(fp);

  /* calling function should have already done this */
  if(!global_user_prefs)
     hdf_init(&global_user_prefs);
     

  /* set the values we just read from the old format file */     
  hdf_set_value(global_user_prefs, "id", id);      
  hdf_set_value(global_user_prefs, "realname", realname);   
  
  /* write the values to the new format file */
  store_user_prefs(username);

  unlink(id_fname);   /* delete the old format file - not needed */

}  








static void load_user_prefs(const char *username)
{
  char path[MAX_PATH +1];

  if(global_user_prefs)
        free_user_prefs();

  hdf_init(&global_user_prefs);
   
  get_user_prefs_path(username,path);

  if(hdf_read_file(global_user_prefs, path) != STATUS_OK)
       {
         convert_old_id_file(username);
         if(!global_user_prefs)
            hdf_init(&global_user_prefs);
            
         if(hdf_read_file(global_user_prefs, path) != STATUS_OK)
	     cs_critical_error(ERR_LOAD_USER_PREFS, path);
       }
}   





/* the default value for any user pref is a blank string.  This can be over-ridden
** on a case-by-case basis here.
*/
static 
void get_default_user_pref(const char *pref_name, char *value, int max_len)
{

 if(!strcmp(pref_name, "realname"))
    *value = '\0';
 else if(!strcmp(pref_name, "id"))
    *value = '\0';
 else 
     *value = '\0';
   
}



/* assumes value is a character array of size max_len + 1 */
void get_user_pref(const char *username, const char *pref_name, char *value, int max_len)
{

 
 if(!global_user_prefs)
     load_user_prefs(username);
 
 strncpy(value, hdf_get_value(global_user_prefs, pref_name, UNKNOWN_USER_PREF_VALUE), max_len + 1);
 *(value + max_len) = '\0';
 strtrm(value);   /* shared_strtrm.c */
 
 if(!strcmp(value,UNKNOWN_USER_PREF_VALUE))
   get_default_user_pref(pref_name, value, max_len);
   
}



void set_user_pref(const char *username, const char *pref_name, const char *value)
{
 
 if(!global_user_prefs)
    load_user_prefs(username);
    
 hdf_set_value(global_user_prefs, pref_name, value);

}





/** returns realname for person represented by username
*** realname is an empty string if data can't be read
**/

void
get_central_user_realname (const char *username, char *realname)
{
 get_user_pref(username, "realname", realname, MAX_NAME);
 free_user_prefs();
}  







/** fills in user struct with available values
*** from the central user store
*** set_capture is used for capture mode */
void
get_central_user_info (const char *username, SESSION *user, int set_capture_flag)
{
 
  get_user_pref(username, "id", user->id, MAX_ID);
  get_user_pref(username, "realname", user->realname, MAX_NAME);
  free_user_prefs();
  
  
  strncpy(user->username, username, MAX_USERNAME + 1); 
  *(user->username + MAX_USERNAME) = '\0';

  if(set_capture_flag)   /* then alias gets a special value */
      strcpy(user->alias, ALIAS_CAPTURE_FLAG);    /* shared_access.h */
  else
     strcpy(user->alias,"anonymous");


  /* remaining data items are not used for central user
  ** but let's give them some reasonable values anyway
  */


  user->team = 'A';
  user->group = STUDENT;
}  





int create_central_letter_dir (char letter)
{
 char letter_dir[MAX_PATH + 1];

 snprintf(letter_dir, MAX_PATH + 1, "../%s/%c", USERS_DIR, letter);
 if(!file_exists(letter_dir))  /* shared_file_util.c */
  {
   if(mkdir(letter_dir, 0770))
       return 0;
  }
 return 1;
}



int create_central_user_dir(const  char *username)
{
 char dir_name[MAX_PATH + 1];
 char dir;
 
 dir = sub_dir_name(username);   /* shared_authenticate.c */
 snprintf(dir_name, MAX_PATH + 1, 
           "../%s/%c/%s", USERS_DIR, dir, username);
 

if(mkdir(dir_name, 0770))
  return 0;
  
 return 1;  

}






/* writes the user's prefs.hdf file for the first time */

int write_central_id_file (const char *realname, 
					const char *username, 
		  		           const char *id)
{

 free_user_prefs();
 hdf_init(&global_user_prefs);
 hdf_set_value(global_user_prefs, PREF_REALNAME, realname);
 hdf_set_value(global_user_prefs, PREF_ID, id);
 store_user_prefs(username);
 
 return 1;
}




static 
int course_already_listed(const  char *username, 
				 const char *crs)
{
   char path[MAX_PATH + 1];
   char line[200];
   FILE *fp;
   char dir;

   dir = sub_dir_name(username);  /* shared_authenticate.c */
   snprintf(path, MAX_PATH + 1, 
               "../%s/%c/%s/%s",  USERS_DIR, dir, 
                               username,COURSE_LIST_FNAME);
    fp = fopen(path,"r");
    if(!fp)
      return 0;
    if(get_shared_lock(fileno(fp), 0))
    {
	fclose(fp);
	return 0;
    }
   while(fgets(line,200,fp))
   {
    strtrm(line);   /* shared_strtrm.c */
    if(!strcmp(line,crs))
    {
     release_lock(fileno(fp));
     fclose(fp);
     return 1;
    }
   }
  release_lock(fileno(fp));
  fclose(fp);
  return 0;
}					





int add_course(const  char *username, 
		       const char *crs)
{
char path[MAX_PATH + 1];
FILE *fp;
char dir;

 dir = sub_dir_name(username);  /* shared_authenticate.c */
 snprintf(path, MAX_PATH + 1, 
               "../%s/%c/%s/%s", USERS_DIR, dir, 
                               username,COURSE_LIST_FNAME);
 fp = fopen(path,"a");
 if(!fp)
    return 0;
 get_exclusive_lock(fileno(fp), 1);
 fprintf(fp,"%s\n",crs);
 release_lock(fileno(fp));
 fclose(fp);
 
 return 1;
}					




int
update_central_course_file( const char *username,
                                       const char *crs)
{
  if(!course_already_listed(username,crs))
    return add_course(username,crs);
  
  return 1;  
}    









/* return NEW_USER if userid is new
   return EXISTING_USER if userid already exists && id == id
   return CONFLICT if userid already exists but id !=id  */

USER_STATUS
central_user_status ( const char *username, const char *id)
{
 DIR *dir_ptr;
 char directory_name[MAX_PATH +1];
 char id_line[MAX_ID + 1];
 char dir;

 dir = sub_dir_name(username);  /* shared_authenticate.c */
 snprintf(directory_name, MAX_PATH +1, 
               "../%s/%c/%s", USERS_DIR, dir, username);
 dir_ptr = opendir(directory_name);
 if(!dir_ptr)         
   return NEW_USER;
 else     /* username already exists */
 {
  closedir(dir_ptr);

  get_user_pref(username, "id", id_line, MAX_ID);
  free_user_prefs(username);
 
  if( !strcmp(id_line, id))   /* id == id */
   return EXISTING_USER;
  else
   return CONFLICT;                  /* id !=id */
 }
}





/* returns true if a central directory exists for 'username'
*/
int
central_username_exists ( const char *username)
{
 DIR *dir_ptr;
 char directory_name[MAX_PATH +1];
 char dir;

 dir = sub_dir_name(username);   		/* shared_authenticate.c */
 snprintf(directory_name, MAX_PATH +1, 
               "../%s/%c/%s",  USERS_DIR, dir, username);
 dir_ptr = opendir(directory_name);
 if(!dir_ptr)         
   return 0;      /* no directory exists, so the username doesn't exist */
 else
  {
   closedir(dir_ptr);
   return 1;     /* the username is in use */
  }   
}



/* return NEW_USER if userid is new
   return EXISTING_USER if userid already exists && id == id
   return CONFLICT if userid already exists but id !=id  */

USER_STATUS
check_central_username ( const char *username, const char *id)
{
 DIR *dir_ptr;
 char directory_name[MAX_PATH +1];
 char id_line[MAX_ID + 1];
 char dir;

 if(!strlen(username))
    return CONFLICT;
    
 dir = sub_dir_name(username);   /* shared_authenticate.c */
 snprintf(directory_name, MAX_PATH +1, 
               "../%s/%c/%s",  USERS_DIR, dir, username);
 dir_ptr = opendir(directory_name);
 if(!dir_ptr)         
   return NEW_USER;
 else     /* username already exists */
 {
  closedir(dir_ptr);

  get_user_pref(username, "id", id_line, MAX_ID);
  free_user_prefs();
  
  if( !strcmp(id_line, id))   /* id == id */
   return EXISTING_USER;
  else
   return CONFLICT;                  /* id !=id */
 }
}




