#include <cstdlib> // rand() and srand()
#include <ctime>   // system time
#include <fstream>
#include <iomanip>  // setw() and formatting
#include <iostream> // basic i/o
#include <string>
#define MAX_HOUSE_SIZE 8
using namespace std;

struct StudentNode {
  string lastname = "";
  string firstname = "";
  string house = "";
  StudentNode *nextStudent = nullptr;
};

struct House {
  string name = "";
  unsigned number = 0;
  StudentNode *first = nullptr;
  StudentNode *current = nullptr;
};

void addStudent(StudentNode *s, House *h) {
  if (h->number < MAX_HOUSE_SIZE) {
    // if we're adding the first student
    if (h->first == nullptr) {
      h->first = s;
      h->current = h->first;
    } else {
      h->current->nextStudent = s;
    }
    h->current = s;
    h->number++;
  } else {
    cout << "ERROR: House is full.\n";
  }
  return;
}

int main() {
  StudentNode *s = new StudentNode;
  House *h = new House;
  House houses[4];
  string houseNames[] = {"Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"};
  string temp;
  ifstream infile;
  string filename = "students.csv";
  int n = 0;
  int m = 0;
  int houseNum;
  bool validHouse;

  // seed the PRNG
  unsigned seed;
  seed = time(0);
  srand(seed);

  // print the initial state of Houses
  cout << "Initializing Houses:\n";
  for (int i = 0; i < 4; i++) {
    houses[i].name = houseNames[i];
    cout << houses[i].name << ": " << houses[i].number << endl;
  }
  cout << "********************\n";
  
  // Get the filename from the user
  // cout << "Please enter the filename: ";
  // cin >> filename;

  // Open the file the user specified
  infile.open(filename);

  // If the file successfully opened, process it.
  if (infile) {
    // Read the members from the file and display them.
    cout << "\nThe sorting hat says:\n";
    while (n < 30) {
      // getline(string, token, delimiter);
      getline(infile, temp, ',');
      s->lastname = temp;
      getline(infile, temp);
      s->firstname = temp;
      cout << setw(2) << right << n + 1 << "). " << s->firstname << " " << s->lastname << ": \n";
      validHouse = false;
      houseNum = rand() % 4;
      do {
        // only add the student if there's room
        if (houses[houseNum].number < MAX_HOUSE_SIZE) {
          s->house = houseNames[houseNum];
          validHouse = true;
          h = &houses[houseNum];
          addStudent(s, h);
          cout << "Adding: " << s->firstname << " " << s->lastname
               << " to House " << s->house << endl;
        }else{
          cout << houseNames[houseNum] << " is full...choosing another.\n";
          houseNum = (houseNum + 1) % 4;
        }
        // if the house is full, choose another!
      } while (not validHouse);
      cout << s->house << " now has " << houses[houseNum].number
           << " student(s).\n\n";
      n++;
      // now dynamically create the next student
      // Declaration of s: StudentNode *s = new StudentNode;
      s = new StudentNode;
    }
    // Close the file.
    infile.close();
  } else {
    // Display an error message.
    cout << "Error opening " << filename << ".\n";
  }
  cout << "\n******************\nThe total is: " << n << endl;

  cout << "\n********************************\n";
  cout << "Dynamic List following pointers:\n";
  cout << "********************************\n";
  for (int x = 0; x < 4; x++) {
    houses[x].current = houses[x].first;
    cout << "\n" << houses[x].name << " [" << houses[x].number << "]:\n";
    m = 1;
    // if there is no next student, we're at the end.
    while (houses[x].current->nextStudent != nullptr) {
      cout << setw(2) << right << m << "). " << houses[x].current->firstname
           << " " << houses[x].current->lastname << endl;
      houses[x].current = houses[x].current->nextStudent;
      m++;
    }
    cout << setw(2) << right << m << "). " << houses[x].current->firstname
         << " " << houses[x].current->lastname << endl;
  }
  return 0;
}
