#include "Student.h"

//---------------------------------------------------------------
// Constructor
//---------------------------------------------------------------
Student::Student(void) : gpa(0.0) {};
Student::Student(const Student& s) { *this = s; }
Student::Student(string i,string n,string d,string a,string p,string t,string cur,string prev):
  sid(i), name(n), dob(d), address(a), phone(p), type(t) {
  if(!prev.empty()) setTranscript(prev);
  if(!cur.empty()) setSchedule(cur);
  setGPA();
}

//---------------------------------------------------------------
// Assignment operator
//---------------------------------------------------------------
const Student& Student::operator=(const Student& s) {
  if (this == &s) return *this;

  sid      = s.getID();
  name     = s.getName();
  dob      = s.getDOB();
  address  = s.getAddress();
  phone    = s.getPhone();
  type     = s.getType();
  gpa      = s.getGPA();
  schedule = s.getSchedule();
  transcript = s.getTranscript();
  
  return *this;
}

//---------------------------------------------------------------
// Function returns the student id number
//---------------------------------------------------------------
string Student::getID()      const { return sid;    }

//---------------------------------------------------------------
// Function returns the student name
//---------------------------------------------------------------
string Student::getName()    const { return name;   }

//---------------------------------------------------------------
// Fucntion returns the student date of birth
//---------------------------------------------------------------
string Student::getDOB()     const { return dob;    }

//---------------------------------------------------------------
// Function returns the student address
//---------------------------------------------------------------
string Student::getAddress() const { return address;}

//---------------------------------------------------------------
// Function returns the student phone number
//---------------------------------------------------------------
string Student::getPhone()   const { return phone;  }

//---------------------------------------------------------------
// Function return the student type
//---------------------------------------------------------------
string Student::getType()    const { return type;   }

//---------------------------------------------------------------
// Function returns the student GPA
//---------------------------------------------------------------
float  Student::getGPA()     const { return gpa;    } 


//---------------------------------------------------------------
// Function returns the student grade for course
//---------------------------------------------------------------
inline string Student::getGrade(string course) {
  return gradetostring(transcript[course]);
}


//---------------------------------------------------------------
// A student has satisfied the prerequisite if 
// the prereg is listed in his/her transcript.
//---------------------------------------------------------------
bool Student::satisfiedPrereq(string prereq) {
  map<string,Grade>::iterator i = transcript.find(prereq);
  return( i != transcript.end() );
}


//---------------------------------------------------------------
// Convert enum Grade -> String
//---------------------------------------------------------------
inline string Student::gradetostring(Grade g) {
  string s;
  switch(g) {
  case A: s = "A"; break;
  case B: s = "B"; break;
  case C: s = "C"; break;
  case D: s = "D"; break;
  case F: s = "F"; break;
  }
  return s;
}

//---------------------------------------------------------------
// Convert String -> enum Grade
//---------------------------------------------------------------
inline Grade Student::stringtograde(string g) {
    Grade ga;
    if( g == "A" ) ga = A;
    if( g == "B" ) ga = B;
    if( g == "C" ) ga = C;
    if( g == "D" ) ga = D;
    if( g == "F" ) ga = F;
    return ga;
}

//---------------------------------------------------------------
// Returns the student's transcript (Hashtable)
//---------------------------------------------------------------
const map<string,Grade> Student::getTranscript() const {
  return transcript;
}

//---------------------------------------------------------------
// Returns the student's courses for the current semester(vector)
//---------------------------------------------------------------
const vector<string> Student::getSchedule() const {
  return schedule;
}


//---------------------------------------------------------------
// Parse a CSV into separate tokens and add to the 
// schedule vector.
//---------------------------------------------------------------
bool Student::setSchedule(string a) {
  Tokenizer t(a,',');
  while(t.hasMoreTokens()) {
    schedule.push_back(t.getToken());
    t++;
  }
  return true;
}

//---------------------------------------------------------------
// Parse a CVS into separate tokens and add to the 
// transcript hashtable (mapping course -> grade)
//---------------------------------------------------------------
bool Student::setTranscript(string a) {
  Tokenizer t(a,',');
  while(t.hasMoreTokens()) {
    string course = t.getToken(); t++;
    Grade g = stringtograde(t.getToken()); t++;
    transcript.insert(make_pair(course,g));
  }
  return true;
}

//---------------------------------------------------------------
// assign grade for course
//---------------------------------------------------------------
bool Student::setGrade(string course, string grade) 
{
  vector<string>::iterator i = schedule.begin();
  while( (i!=schedule.end()) && ((*i)!=course) ) i++;

  if(i!=schedule.end()) { 
    cout << "Found course in Student Record " << endl;
    schedule.erase(i);
  }

  cout << "Grade: " << stringtograde(grade);

  transcript[course] = stringtograde(grade);

  cout << *this << endl;
  return true;
}

//---------------------------------------------------------------
// register student for course
//---------------------------------------------------------------
bool Student::setRegistration(string course)
{
  schedule.push_back(course);
}


//---------------------------------------------------------------
// Calculate GPA
//---------------------------------------------------------------
bool Student::setGPA() {
  int numgrades = 0;
  map<string,Grade>::iterator mit;
  for(mit = transcript.begin(); mit != transcript.end(); mit++) {
    Grade g = mit->second;
    switch(g) {
    case A: gpa += 4.0; break;
    case B: gpa += 3.0; break;
    case C: gpa += 2.0; break;
    case D: gpa += 1.0; break;
    case F: gpa += 0.0; break;
    }
    numgrades++;
  }
  gpa = numgrades == 0 ? 4.0 : gpa/(float)numgrades;
  return true;
}

/************ I n p u t   O p e r a t o r **************/
istream& operator>> (istream& in, Student& s)
{
  char* input = new char[50];
  string temp;

  // Input student id
  cout << "Student ID [" << s.sid << "] : ";
  in.get(input,50,'\n');
  in.ignore();
  temp = input;
  if( temp.length() > 0 ) s.sid = temp;

  // Input student name
  cout << "Name [" << s.name <<"] : "; 
  in.get(input,50,'\n');
  in.ignore();
  temp = input;
  if( temp.length() > 0 ) s.name = temp;

  // Input student date of birth
  cout << "Date of Birth [" << s.dob <<"] : "; 
  in.get(input,50,'\n');
  in.ignore();
  temp = input;
  if( temp.length() > 0 ) s.dob = temp;

  // Input address
  cout << "Address [" << s.address <<"] : "; 
  in.get(input,50,'\n');
  in.ignore();
  temp = input;
  if( temp.length() > 0 ) s.address = temp;

  // Input phone
  cout << "Phone [" << s.phone <<"] : "; 
  in.get(input,50,'\n');
  in.ignore();
  temp = input;
  if( temp.length() > 0 ) s.phone = temp;

  // Input type
  cout << "Type [" << s.type <<"] : "; 
  in.get(input,50,'\n');
  in.ignore();
  temp = input;
  if( temp.length() > 0 ) s.type = temp;

  return in;
}

/************ O u t p u t   O p e r a t o r **************/
ostream& operator<< (ostream& out, Student& s)
{
  vector<string>::iterator vit;
  map<string,Grade>::iterator mit;

  out << "S t u d e n t" << endl;
  out << "ID: " << s.sid << endl;
  out << "Name: " << s.name << endl;
  out << "Birth: " << s.dob << endl;
  out << "Address: " << s.address << endl;
  out << "Phone: " << s.phone << endl;
  out << "Type: " << s.type << endl;
  out << "GPA: " << s.gpa << endl;
  out << "Schedule: " << endl;
  for(vit = s.schedule.begin(); vit != s.schedule.end(); vit++)
    out << "      " << *vit << endl;
  out << "Transcript: " << endl;
  for(mit = s.transcript.begin(); mit != s.transcript.end(); mit++)
    out << "      " << mit->first << "   " << mit->second << endl;

  return out;
}

//---------------------------------------------------------------
// Constructor
//---------------------------------------------------------------
bool Student::operator== (const Student& s) {
  return( sid == s.getID() );
}

//---------------------------------------------------------------
// Constructor
//---------------------------------------------------------------
bool Student::operator!= (const Student& s) {
  return( sid != s.getID() );
}

//---------------------------------------------------------------
// Convert a student object into a string delimeted by the 
// ':' character.  This is a useful function for the File 
// operations, which write lines to files.
//---------------------------------------------------------------
string Student::toString(void)
{
  char* buf = new char[50];

  vector<string>::iterator vit;
  map<string,Grade>::iterator mit;

  string s = 
    sid+":"+
    name+":"+
    dob+":"+
    address+":"+
    phone+":"+
    type+":";
  sprintf(buf,"%lf:",gpa);
  string s2(buf);
  s += s2;

  string s3;
  for(vit = schedule.begin(); vit != schedule.end(); vit++)
    s3+= (*vit+string(","));
  s += s3.substr(0,s3.length()-1) + ":";

  string s4;
  for(mit = transcript.begin(); mit != transcript.end(); mit++)
    s4 += (mit->first+","+gradetostring(mit->second)+",");
  s += s4.substr(0,s4.length()-1);

  return s;
}

//---------------------------------------------------------------
// Convert a ':' delimeted string to a Student object; 
// This is a useful function for the File operations which 
// read lines from files.
//---------------------------------------------------------------
Student Student::parse(string s)
{
  Tokenizer t(s,':');
  cout << "In STUDENT PARSE" << endl;

  return( Student
	  (t.getToken(0),
           t.getToken(1),
           t.getToken(2),
           t.getToken(3),
           t.getToken(4),
           t.getToken(5),
           t.getToken(7),
           t.getToken(8)));
}
