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

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

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

House addStudent(StudentNode *s, House h) {
  if (h.number < MAX_HOUSE_SIZE) {
    h.members[h.number] = *s;
    h.number++;
  } else {
    cout << "ERROR: House is full.\n";
  }
  return h;
}

int main() {
  StudentNode *s = new StudentNode;
  House houses[4];
  string houseNames[] = {"Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"};

  cout << "Houses:\n";
  for (int i = 0; i < 4; i++) {
    houses[i].name = houseNames[i];
    cout << houses[i].name << ": " << houses[i].number << endl;
  }

  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);

  // 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 << "The sorting hat says:\n";
    while (n < 30) {
      // getline(string, token, delimiter);
      getline(infile, temp, ',');
      s->lastname = temp;
      getline(infile, temp);
      s->firstname = temp;
      cout << n + 1 << "). " << s->firstname << " " << s->lastname << ": ";
      do {
        validHouse = false;
        houseNum = rand() % 4;
        // only add the student if there's room
        if (houses[houseNum].number < MAX_HOUSE_SIZE) {
          s->house = houseNames[houseNum];
          validHouse = true;
          houses[houseNum] = addStudent(s, houses[houseNum]);
        }
        // if the house is full, choose another!
      } while (not validHouse);
      cout << s->house << endl;
      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";
  }

  for (int x = 0; x < 4; x++) {
    houses[x].first = &houses[x].members[0];
    houses[x].current = houses[x].first;
    cout << "\n" << houses[x].name << ": [" << houses[x].number << "]\n";
    for (int y = 0; y < houses[x].number; y++) {
      cout << "\n"
           << setw(2) << right << y + 1 << "). "
           << houses[x].members[y].lastname << ", "
           << houses[x].members[y].firstname;
      while (houses[x].current->nextStudent == nullptr and
             &houses[x].members[y] != houses[x].current) {
        houses[x].current->nextStudent = &houses[x].members[y];
        houses[x].current = houses[x].current->nextStudent;
      }
    }
    cout << endl;
  }
  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;
}
