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

#define MAX_PATH 256       

int global_count;
       
typedef enum {DELETE, LIST, RESTORE} COMMAND;








static void
show_help()
{
 puts(
 "\n\nManhattan stores its messages in files organized within directories on your filesystem.\n"
 "In versions earlier than 3.3, a directory for each 'module' was created for each student or\n"
 "or teacher in each classroom.  For example, to support Manhattan's Handouts/Notices directory\n"
 "a directory named 'handouts' was created for each student and teacher in the classroom.\n"
 "The same was automatically done for each of Manhattan's 13 modules.  These many directories\n"
 "were created at the time the class was created by the Manhattan administrator, and whenever a new\n"
 "student or teacher was added to a classroom.\n\n"
 "In practice, since most classrooms do not use all of Manhattan's modules, most of these directories\n"
 "remained completely empty, resulting in wasted disk space and an unnecessarily large number of\n"
 "files that had to be supported by the disk operating system.\n\n"
 "Manhattan version 3.3 and beyond also uses directories to organize its message files, but the\n"
 "directories are created on demand, at the moment they are needed.\n\n"
 "This utility can be used to delete, list, or restore empty directories within your Manhattan\n"
 "installation.  You should run it to clean up unneeded empty directories after you have upgraded\n"
 "to Manhattan 3.3 or later from Manhattan 3.2 or earlier.\n\n"
 "This utility must be run from the 'src' directory of your Manhattan installation.  It will search\n"
 "../courses for the empty directories.\n\n"
 "You must supply exactly one of the following switches with no other arguments:\n\n"
 "-h     (or no switch) - shows this help screen\n"
 "-t     test, lists and counts the directories that would be deleted if you had used the -d switch. DOES NOT ACTUALLY DELETE ANY DIRECTORIES OR FILES.\n"
 "-d     delete, deletes all empty directories not required by Manhattan 3.3 or later.\n"
 "-r     restore, restores all directories deleted by -d USE THIS ONLY IF YOU NEED TO REVERT BACK TO MANHATTAN 3.2 or earlier.\n\n"
 "BE ABSOLUTELY CERTAIN NO USERS ARE ON MANHATTAN WHEN USING THE -d OR -r SWITCHES!!!!!\n");
 }
 
 
static void
confirm_choice(COMMAND cmd)
{

#define DEL_STRING  "I AM SURE THERE ARE NO ACTIVE USERS ON THIS MANHATTAN INSTALLATION."
#define RESTORE_STRING "RESTORE THE DIRECTORIES, I KNOW WHAT I AM DOING."

 char msg[101];
 
 puts("\n*** You can use the -h switch to read the full help file. ***\n");
 switch(cmd)
 {
  case DELETE:  
    puts(
    "This will permanently delete all empty directories for all Manhattan classrooms\n"
    "stored in the ../courses directory of this Manhattan installation that are not \n"
    "required by Manhattan version 3.3 or later.\n\n"
    "Make sure no one is using this Manhattan installation before continuing!!!\n\n"
    "To continue, type the following exactly as it appears, and hit ENTER:\n\n");
    
    printf("%s\n\n", DEL_STRING);
    
    
    fgets(msg, 100, stdin);
    if(strstr(msg, DEL_STRING))
      puts("Deleting all unnecessary directories ...\n\n");
    else
     {
       puts("You didn't type the magic words, so quitting....\n");     
       exit(0);
     }
   break;
   
   
  case LIST:
    puts("Hit ENTER to list the directories that will be deleted if you use the -d switch\n"
         "or Ctrl-C to abort:\n");
    fgets(msg,100,stdin);
    break;
    

  case RESTORE:  
    puts("This will re-create the directories deleted by using the -d switch with this utility.\n");
    puts("THE ONLY REASON YOU SHOULD EVER HAVE TO DO THIS IS IF YOU NEED TO REVERT BACK TO AN OLDER");
    puts("VERSION OF MANHATTAN (that is, version 3.2 or earlier)\n\n");
    puts("You will have to fix the file permissions yourself.  You should really think long and hard");
    puts("about why you need to do this.\n");
    puts("To restore the directories, type the following exactly as it appears, and hit ENTER:\n\n");

    printf("\n\n%s\n\n", RESTORE_STRING);
    
    
    fgets(msg, 100, stdin);
    if(strstr(msg, RESTORE_STRING))
      puts("Restoring directories...\n\n");
    else
     {
       puts("You didn't type the magic words, so quitting....\n");     
       exit(0);
     }
   break;
     
   }
   
#undef DEL_STRING
#undef RESTORE_STRING        
}     
     
     
    
    
  


static void
get_command(int argc, const char *argument, COMMAND *cmd)
{

 if( (argc != 2)              || 
    (
     strcmp(argument, "-d")  && 
     strcmp(argument, "-t")  && 
     strcmp(argument, "-r")  ))
  {
    show_help();
    exit(0);
  }
  
  *cmd = LIST;
  if(!strcmp(argument, "-d"))
     *cmd =DELETE;
  else
    if(!strcmp(argument, "-t"))
      *cmd = LIST;
    else
      if(!strcmp(argument, "-r"))
         *cmd = RESTORE; 

  confirm_choice(*cmd);
}











static void
do_command(char *target_dir, COMMAND cmd)
{
 DIR *dir_p;
 struct dirent *dir_entry_p;
 int empty_dir = 1;
 int is_dir = 0;
 
 dir_p = opendir (target_dir);
 if (dir_p)
   { 
    is_dir = 1;
    while ((NULL != (dir_entry_p = readdir (dir_p))) && empty_dir)
       {  
        if (strcmp (dir_entry_p->d_name, ".")
	      && strcmp (dir_entry_p->d_name, ".."))
         {
           empty_dir = 0;
         }  
       }  
    closedir(dir_p);
   }     
 
 switch(cmd)
  {
   case DELETE:  if(is_dir && empty_dir)
                  {
                   if(rmdir(target_dir))
                      perror(target_dir);
                   else
                    {
                      printf("Removed: %s \n", target_dir);                      
                      global_count++;
                    }  
                   }
                   break;
                   
   case LIST:    if(is_dir && empty_dir)
                   {
                     printf ("Would remove: %s \n", target_dir);
                     global_count++;
                   }  
                break;    
                                          
      
  case RESTORE:  if(!is_dir)
                   {
                     if(mkdir(target_dir, 0777))
                        perror(target_dir);
                     else
                      {
                       printf("Created directory: %s\n", target_dir);
                       global_count++;
                      } 
                    }
                    break;       
                        
   
  default: break;
  
  
  }  
}  
 
 
 
 
 

static
void execute_command (COMMAND cmd)
{
  char *dirlist[] = {"anon", "assign", "discuss", "handouts", "inet", "lectures", "lounge", "mail", "selftest", "surveys", "team", "team_teach", "chat", "grades", "podcasts", "" };
  int i;
  char people_dir[MAX_PATH + 1];
  char target_dir[MAX_PATH + 1];
  char group_dir[MAX_PATH + 1];
  

  DIR *group_dir_p;
  struct dirent *group_dir_entry_p;


  DIR *course_dir_p;
  struct dirent *course_dir_entry_p;
  
  DIR *people_dir_p;
  struct dirent *people_dir_entry_p;
  
  
  group_dir_p = opendir("../courses");
  if(!group_dir_p)
    {
      perror("Can't open ../courses directory.  This utility should be run from the 'src' directory of your installation.");
      exit(1);
    }
  else
   {  
    while (NULL != (group_dir_entry_p = readdir (group_dir_p)))   /* for each course group */
    {  
     if (strcmp (group_dir_entry_p->d_name, ".")
         && strcmp (group_dir_entry_p->d_name, "..") )
        {
          snprintf(group_dir, MAX_PATH, "../courses/%s", group_dir_entry_p->d_name);
          course_dir_p = opendir(group_dir);
          if(!course_dir_p)
            {
              perror(group_dir);
              puts("Skipping...\n");
             }
           else
            {
               while (NULL != (course_dir_entry_p = readdir (course_dir_p)))  /* for each course */
                {  
                 if (strcmp (course_dir_entry_p->d_name, ".")
                     && strcmp (course_dir_entry_p->d_name, "..")
                     && strcmp (course_dir_entry_p->d_name, "description.txt") )
                  {
                     snprintf(people_dir, MAX_PATH, "%s/%s/people", group_dir, course_dir_entry_p->d_name);
                     people_dir_p = opendir(people_dir);
                     if(!people_dir_p)
                       {
                        perror(people_dir);
                        puts("Skipping...");
                       }
                     else
                       {    
                         puts("\n");
                         while (NULL != (people_dir_entry_p = readdir (people_dir_p)))
                          {  
                            if (strcmp (people_dir_entry_p->d_name, ".")
                              && strcmp (people_dir_entry_p->d_name, ".."))
                              {
                               for(i=0; *dirlist[i]; i++)
                                {
                                 snprintf(target_dir, MAX_PATH, "%s/%s/%s",people_dir, people_dir_entry_p->d_name,dirlist[i]);
                                 do_command(target_dir, cmd);
                                }
                               } 
                          }
                         closedir(people_dir_p); 
                        }
                  }
                 
                }   
               closedir(course_dir_p);   
            }
        }
    }
    closedir(group_dir_p);
   }     

 printf("\n\nProcessed %d directories.\n",global_count);

}

                    
  
    







int main(int argc, char **argv)
{
  COMMAND cmd;
  
  get_command(argc, argv[1], &cmd);
  execute_command(cmd);
  
  return 0;
}
  


