// The final form of the SortingHatSim:
// All dynamic using pointers and no fixed-length arrays.
// Functions take only pointers as parameters.

#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;
  House *next = 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 *f = h; // first House
  House *c = f; // current 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++) {
    h->name = houseNames[i];
    cout << h->name << " memory address: " << h << endl;
    cout << "number of members: " << h->number << endl;
    if (i < 3) {
      h = new House;
      c->next = h;
      c = h;
    } else {
      c->next = f; // loop the pointer around back to first
    }
  }
  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;
      // Make c = f (the first House)
      c = f;
      // We have to get to the matching house.
      while (c->name != houseNames[houseNum]) {
        c = c->next;
      }

      do { // checking House members loop
        cout << "DEBUG: checking " << houseNames[houseNum] << endl;
        cout << "DEBUG: c->name: " << c->name << endl;
        // only add the student if there's room
        if (c->number < MAX_HOUSE_SIZE) {
          cout << "DEBUG: " << c->name << " is not full.\n";
          s->house = c->name;
          validHouse = true;
          addStudent(s, c);
          cout << "Adding: " << s->firstname << " " << s->lastname
               << " to House " << c->name << endl;
        } else {
          cout << c->name << " is full...choosing another.\n";
          if (c->next != nullptr) { // if there's another in the list
            c = c->next;            // advance
            if (c == f) {
              cout << "DEBUG: reached the end of the House list.\n";
            }
            cout << "DEBUG: advancing to House " << c->name << endl;
            houseNum = ((houseNum + 1) % 4);
          }
        }
        // if the house is full, choose another!
      } while (not validHouse);
      cout << s->house << " now has " << c->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";
  c = f;                 // the first house
  c->current = c->first; // the first student
  cout << "DEBUG: Current house is now: " << c->name << ", address: " << c
       << endl;
  cout << "DEBUG: Current student is now: " << c->current->firstname << " "
       << c->current->lastname << endl;
  do {
    cout << "\n" << c->name << " [" << c->number << "]:\n";
    m = 1;
    // if there is no next student, we're at the end.
    while (c->current->nextStudent != nullptr) {
      cout << setw(2) << right << m << "). " << c->current->firstname << " "
           << c->current->lastname << endl;
      c->current = c->current->nextStudent;
      m++;
    }
    // print the last student
    cout << setw(2) << right << m << "). " << c->current->firstname << " " << c->current->lastname << endl;
    // advance to the next house
    c = c->next;
    c->current = c->first; // the first student
    cout << "DEBUG: Current house is now: " << c->name << ", address: " << c << endl;
    cout << "DEBUG: Current student is now: " << c->current->firstname << " " << c->current->lastname << endl;
  } while (c != f); // if we looped back around, stop output.

  return 0;
}
