#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;

#define check( s, a, b ) { \
    if( (a) != (b) ) { \
        cout << "## FAIL (" << (s) << "): " << (a) << " != " << (b) << endl; \
        exit(1); \
    } \
    cout << "## PASS (" << (s) << "): " <<  (a) << endl; \
    }

/* EX 1
 *
class Student {
    string lname, fname;
    int year;
    vector<string> classes;
public:
    Student(string lastname, string firstname) { lname = lastname; fname = firstname, year=1; classes.clear(); }
    string get_name() { return lname + " " + fname; }
    int get_year() { return year; }
    void promote() { year = (!year || year >= 4) ? 0 : year+1; }
    bool graduated() { return !year; }
    void enroll( string cname ) { classes.push_back( cname ); }
    vector<string> get_classes() { return classes; }
};
*/

 class Student {
     string lname, fname;
     int year;
     vector<string> cls;
     int sid; //ex2
     
 public:
     Student(string lastname, string firstname);
     string get_name() const { return lname + " " + fname; }
     int get_year() { return year; }
     void set_year( int yr ) { year = yr; }
     void promote() { year = (!year || year >= 4) ? 0 : year+1; }
     bool graduated() { return !year; }
     void enroll( string cname ) { cls.push_back( cname ); }
     string get_class(int i) { return cls[i]; }
     //ex2 {
     int get_sid() { return sid; }
     //}
     //ex3 {
     void drop( string cname );
     int cls_cnt( ) { return (int)cls.size(); }
     //}
     //ex4 {
     Student &operator++() { year++; return *this; }
     Student operator++(int) { Student t = *this; year++; return t; }
     //ex5 {
     friend bool operator<(const Student s1, const Student s2);
     //}
     //ex6 {
     friend ostream &operator<<(ostream &out, const Student &t);
     //}
 };


//ex2
Student::Student(string lastname, string firstname)
{
    lname = lastname;
    fname = firstname;
    year=1;
    cls.clear();
    //ex2
    srand( (unsigned int) time(0) );
    sid = rand();
}

//ex3
void Student::drop(string cname) {
    vector<string>::iterator it = find( cls.begin(), cls.end(), cname );
    if( it != cls.end() )
        cls.erase(it);
    else
        cout << "Not found" << endl;
}

//ex5
bool operator<(Student s1, Student s2) {
    return s1.year < s2.year;
}

//ex6
ostream &operator<<(ostream &out, const Student &t)
{
    out << "Student { name: " << t.get_name() << ", year: " << t.year;
    return out;
}

int main(int argc, const char * argv[]) {
    
    Student s1( "Kim", "Soochul" );
    check( "get_year()", s1.get_year(), 1 );
    check( "get_name()", s1.get_name(), "Kim Soochul" );
    s1.promote();
    check( "get_year()", s1.get_year(), 2 );
    check( "graduated()", s1.graduated(), false );
    s1.enroll( "C++" );
    s1.enroll( "Java" );
    check( "get_class()", s1.get_class(0), "C++" );
    check( "get_class()", s1.get_class(1), "Java" );
    s1.promote(); s1.promote(); s1.promote();
    check( "graduated()", s1.graduated(), true );
    
    //ex2
    check( "get_sid()", s1.get_sid(), s1.get_sid());
    
    //ex3
    s1.drop("C++");
    check( "get_class()", s1.get_class(0), "Java" );
    check( "cls_size()", s1.cls_cnt(), 1 );
    
    //ex4
    s1.set_year(1);
    ++s1;
    check( "prefix++: get_year()", s1.get_year(), 2)
    s1++;
    check( "postfix++: get_year()", s1.get_year(), 3)
    
    //ex5
    Student s2("Lee", "June");
    s2 < s1;
    check( "<", s2 < s1, true );
    
    cout << s1 << endl;
    cout << s2 << endl;
    system( "read" );
    return 0;
}
