//Shawn O'Neil - Hash Table. ADD, DELETE, MEAN, GRADE implemented. PRINT works, but prints the
//entire thing in no particular order.
//CS222 - Winter 03.
#include <iostream>
#include <string>
#include "htable.h"
//#include "list.h"
using namespace std;

#define NOTFOUND 1
#define OUTRANGE 2
#define DUPLICATE 3
#define NONONZERO 4


//Hash Table constructor
HTable::HTable()
   {
   for(int i = 0; i < 5; i++)
      {
      scores[i] = 0;
      numbers[i] = 0;
      }
   }

//Hash Table destructor
HTable::~HTable()
   {
   }

//Given a name, looks up its position in the table
int HTable::lookup(string thename)
   {
   int current = 0;
   for(int i = 0; i < thename.length(); i++)
      {
      current = (current*256+(1+(int)(unsigned char)thename[i]))%25013;
      }
   return current;
   }

//Adds a name to the table
void HTable::add(string thename)
   {
   t[lookup(thename)].add(thename);
   }

//deletes a name from the table
void HTable::del(string thename)
   {
   t[lookup(thename)].del(thename, this);
   }

//Sets thenames grade on test number to score, throws outrange if score or test are no good
void HTable::grade(int number, double score, string thename)
   {
   if(score <= 0)
      throw OUTRANGE;
   else if(number != 1 && number != 2 && number != 3 && number != 4 && number != 5)
      throw OUTRANGE;
   else
      {
      t[lookup(thename)].grade(number, score, thename);
      scores[number] += score;
      numbers[number]++;
      }
   }

//returns the mean on test
double HTable::mean(int test)
   {
   if(numbers[test] == 0)
      throw NONONZERO;
   else return scores[test]/numbers[test];
   }

//prints the entire hash table in no particular order
void HTable::print()
   {
   //dont be stupid, you cant full print a hash table! well, ill
   //implement some approximation...
   for(int i = 0; i < 25013; i++)
   t[i].fullprint();
   }

//Used by delete, at the node in the linked list level to fix the totals so the mean funciton will work
void HTable::redogrades(int test, double score)
   {
   scores[test] -= score;
   numbers[test]--;
   }

//Main method, use ADD , DELETE, GRADE, MEAN, and PRINT (only if you really want to...)
int mainf(int argc, char **argv)
   {
   cout << "Happy birthday euclid." << endl;
   HTable t;
   string action;
   int number;
   double grade;
   string name;
   while(cin >> action, cin)
      {
      cin.ignore();
      if(action == "ADD")
         {
         getline(cin, name);
         try
            {
            t.add(name);
            cout << "Successfully added " << name << "." << endl;
            cout << endl;
            }
         catch(int e)
            {
            if(e == NOTFOUND)
               cout << "Could not add, ERROR" << endl;
            else if(e == DUPLICATE)
               cout << "Could not add " << name << ". Name already exists." << endl;
            else if(e == OUTRANGE)
               cout << "Could not add, ERROR" << endl;
            cout << endl;
            }
         }

      else if(action == "PRINT")
         {
         try
            {
         //   cout << endl;
            cout << "Statistics: " << endl;
            t.print();
            cout << endl;
            }
         catch(int e)
            {
            if(e == NOTFOUND)
               cout << "Could not print, ERROR" << endl;
            else if(e == DUPLICATE)
               cout << "Could not print, ERROR" << endl;
            else if(e == OUTRANGE)
               cout << "Could not print, ERROR" << endl;
            cout << endl;
            }
         }

      else if(action == "GRADE")
         {
         cin >> number;
         cin.ignore();
         cin >> grade;
         cin.ignore();
         getline(cin, name);
         try
            {
            t.grade(number, grade, name);
            cout << "Set " << name << "'s grade on test " << number << " to " << grade << "." << endl;
            cout << endl;
            }
         catch(int e)
            {
            if(e == NOTFOUND)
               cout << "Could not grade " << name << ", no match in database." << endl;
            else if(e == DUPLICATE)
               cout << "Could not grade, ERROR" << endl;
            else if(e == OUTRANGE)
               cout << "Could not grade " << name << ", test or number or score out of range" << endl;
            cout << endl;
            }
         }

      else if(action == "DELETE")
         {
         getline(cin, name);
         try
            {
            t.del(name);
            cout << "Successfully deleted " << name << "." << endl;
            cout << endl;
            }
         catch(int e)
            {
            if(e == NOTFOUND)
               cout << "Could not delete " << name << ", no match in database." << endl;
            else if(e == DUPLICATE)
               cout << "Could not delete, ERROR" << endl;
            else if(e == OUTRANGE)
               cout << "Could not delete " << name << ", test number out of range ERROR" << endl;
            cout << endl;
            }
         }

      else if(action == "MEAN")
         {
         cin >> number;
         try
            {
            double mean = t.mean(number);
            if(mean != 0)
               cout << "The mean on test " << number << " is " << t.mean(number) << endl;
            else
               cout << "There are no nonzero means in the database for test " << number << endl;
            cout << endl;
            }
         catch(int e)
            {
            if(e == NOTFOUND)
               cout << "Could not get mean for test " << number << ", no match in database ERROR" << endl;
            else if(e == DUPLICATE)
               cout << "Could not get mean, ERROR" << endl;
            else if(e == OUTRANGE)
               cout << "Could not get mean for test " << number << ", test number out of range." << endl;
            else if(e == NONONZERO)
               cout << "Could not get mean for test " << number << ", no nonzero test scores." << endl;
            cout << endl;
            }
         }

      }
   cout << "Bye, thanks for using." << endl;
   }