#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

#define MAX_LINE 64
#define NUM_DORMS 4

/***
** Structure definition
***/
typedef struct _student {
  char* name;
  int id;
  struct _student* next;
} Student;

typedef struct _dorm {

  char name[32];
  int dormNum;
  int numStudents;

  Student *studentList;
} Dorm;

/***
** One global variable
***/
Dorm dormHash[NUM_DORMS];

/***
** Function prototypes: We have three set of functions
** 1. Part I  : Functions you have to write
** 2. Part II : Functions that you can use for debugging
** 3. Part III: Functions that you dont have to touch
***/
/* Functions that you need to write */
void sortingHat(char* name, int id);
int hatHash(char* name);

/* Function prototypes that you can use for debugging */
void printStudentList(Student* listHead);
void printDorms();

/* Other function prototypes that you dont have to touch */
void usage();
int readStudentFile(char* studentFileName);
void addDorm(char* name, int dormNum);
void releaseMemory();

/* Main function */
int main(int argc, char* argv[]){

  if(argc != 2) {
    usage();
    return -1;
  }

  /** For every student to be added, this function in turn calls sortingHat **/
  printf("Calling Sorting Hat to sort students\n");
  readStudentFile(argv[1]);
  printDorms();

  /* Release all the memory allocated */
  releaseMemory();
  return 0;
}

/**
** COMPLETE THE BELOW FUNCTIONS
**/
void sortingHat(char* name, int id){

  /** TODO:
  ** 1. Add the student with 'name' (and 'id') to one of the houses 
  ** 2. The house for a student with 'name' is given by hathash() function
  **/
}

int hatHash(char* name) {
  /** TODO:
  ** Compute a hash function that maps a student with 'name' to one of the four
  ** houses.
  ** hash(name) = sum of [ name[i] * (i+1) ] for all i
  **/
  return 0;
}

/** 
**    UTILITY FUNCTIONS
** Do not modify below this line 
**/
void usage(){

  fprintf(stderr, "Usage: dormHash <studentFile>\n");
}


void addDorm(char* name, int id){
  assert(id < NUM_DORMS);
  assert(name);
  assert(strlen(name) < 15);
  strcpy(dormHash[id].name, name);
  dormHash[id].dormNum = id;
  dormHash[id].numStudents = 0;
  dormHash[id].studentList = NULL;
}


int buildDorms(){

  addDorm("Gryffindor",0);
  addDorm("Slytherin",1);
  addDorm("Ravenclaw",2);
  addDorm("Hufflepuff",3);
  return 0;
}

int readStudentFile(char* studentFileName){

  char line[MAX_LINE];
  char name[MAX_LINE];
  char* str;
  int id;
  FILE* f;

  if(studentFileName == NULL) {
    printf("Student file name is invalid\n");
    return -1;
  }

  f = fopen(studentFileName, "r");
  if(f == NULL) {
    printf("Student file (%s) is not present\n", studentFileName);
    return -1;
  }

  while(( str = fgets(line, MAX_LINE, f)) != NULL) {

    int len = strlen(line);
    if(len > 1 && line[len-1] == '\n') {
      line[len-1] = '\0';
      len = strlen(line);
      if(len > 0) {
        sscanf(line, "%d %s",&id, name);

        /**
        ** Call sortingHat to appropriately add the student to one of the
        ** houses 
        **/
        sortingHat(name, id);
      }
    }
  }
  fclose(f);
  return 0;
}


void printStudentList(Student* listHead) {

  Student* stu;
  int i=0;
  for(stu = listHead; stu != NULL; stu = stu->next) {
    printf("\tStudent [%d]: %s (%d)\n", i, stu->name, stu->id);
    i++;
  }
}

void printDorms() {

  int i;
  for(i=0; i<NUM_DORMS; i++) {

    printf("Dorm [%d]: %s (%d)\n", dormHash[i].dormNum, dormHash[i].name, dormHash[i].numStudents);
    printStudentList(dormHash[i].studentList);
    printf("---------------------------------------------------------------------\n");
  }
}

void releaseStudentList(Student* studentList) {
  Student * stu = studentList;
  Student * tmp = stu;

  while(stu){
    free(stu->name);
    tmp = stu->next;
    free(stu);
    stu=tmp;
  }
}

void releaseMemory() {

  int i;
  for(i=0; i<NUM_DORMS; i++) {

    releaseStudentList(dormHash[i].studentList);
    dormHash[i].studentList = NULL;
  }

}