/*
 * CSI2131 Winter 2005
 *
 * Assignment#2 Solution : Implementation of The Record class
 *
 * Shantanu Das 
 */


#include "Record.h"


Record::Record()		//Constructor
{
	year = term = key = 0;			// initialize fields to default values.		
	section=' ';
	code = new char[8];
	strcpy(code,"0000000");
	cname=pname=clink=plink=NULL;
	s5 = s6 = s7 = s8 = 0;
	size = 8;
}

Record::~Record()			// Destructor
{
	delete[] code;
	if(cname!=NULL) delete[] cname;
    if(pname!=NULL) delete[] pname;
	if(clink!=NULL) delete[] clink;
	if(plink!=NULL) delete[] plink;
}

long Record::getkey()				// return the key
{
	if(key==0) makekey();
	return key;
}

int Record::getsize()  {  return size;  }

long Record::makekey()	   // construct the key
{
	unsigned char byte1,kfield[4];
	unsigned short int byte23;
	char byte4;
	int code1=0,code2=0;         // code1 is first part(CSI) and code2 is second part(2131) 

	if(strncmp(code,"CEG",3)==0)  code1=0;			// encode the initial part of code
	else if(strncmp(code,"CSI",3)==0)  code1=1;
	else if(strncmp(code,"ELG",3)==0)  code1=2;
	else if(strncmp(code,"GNG",3)==0)  code1=3;
	else if(strncmp(code,"SEG",3)==0)  code1=4;
    code2 = atoi(&(code[3]));				// encode the numeric part of code	

	byte1 = year*3+term;					// byte-1 contains year and term
    byte23 = (code2*5)+code1;				// byte-2 & 3 contains code
	byte4 = section;						// byte-4 contains section

	unsigned short int *kfield12 = (unsigned short int *)&(kfield[1]);  
									//interpret part of the kfield array, as short int

	kfield[0] = byte1;						// write the key part into a char array
	(*kfield12) = byte23;
	kfield[3] = byte4;
	
	key = *((long*)kfield);			// convert the array containing the key, into a long integer

	return key;
}

void Record::setyear(int yr)		// yr = 1997-2081
{
	if (yr < START || yr > (START+84)) {		// check for valid year value
		cerr << "\nError: year out of range :" << yr << endl;
		exit(1);
	}
	year = yr - START;
}

void Record::setterm(int t)		
{
	if (t >= 0 && t < 3)
        term = t;
	else {
		cerr << "\nError: Invalid Semester " << t << endl;
		exit(1);
	}
}

void Record::setcode(const char* cd)		
{
	strncpy(code,cd,7);
}

void Record::setsec(char s)		
{
	if((s < 'A' || s > 'Z') && s!=' ' )			// check for invalid section
		return;
	section = s;
}

void Record::setcname(const char* str, int n)		// set field-5 (Course Name)
{
	if(cname!=NULL) delete[] cname;
	cname = new char[n+1];					// allocate memory for storing the field
	size += (n - s5);						// update size
	s5 = n;
	strncpy(cname,str,n);
}

void Record::setpname(const char* str, int n)		// set field-6 (Prof's Name)
{
	if(pname!=NULL) delete[] pname;
	pname = new char[n+1];					// allocate memory for storing the field
	size += (n - s6);						// update size
	s6 = n;
	strncpy(pname,str,n);
}

void Record::setclink(const char* str, int n)	// set field-7 (Course webpage)
{
	if(clink!=NULL) delete[] clink;
	clink = new char[n+1];					// allocate memory for storing the field
	size += (n - s7);						// update size
	s7 = n;
	strncpy(clink,str,n);
}

void Record::setplink(const char* str, int n)	// set field-8 (Prof's webpage)	
{
	if(plink!=NULL) delete[] plink;
	plink = new char[n+1];					// allocate memory for storing the field
	size += (n - s8);						// update size
	s8 = n;
	strncpy(plink,str,n);
}

int Record::read(istream& fs)
{
	unsigned char byte1,byte4;
	short int numcode = 0;
	
	fs.read((char*)&byte1,1);		// read the first byte
	fs.read((char*)&numcode,2);		// read the next two bytes
	fs.read((char*)&byte4,1);		// read the fourth byte
	if(fs.fail()) return false;

	year = (byte1)/3;				// extract and set year field
	term = (byte1 % 3);				// extract and set term field
	switch(numcode % 5){
		case 0:sprintf(code,"CEG%04d",(numcode)/5);break;
		case 1:sprintf(code,"CSI%04d",(numcode)/5);break;
		case 2:sprintf(code,"ELG%04d",(numcode)/5);break;
		case 3:sprintf(code,"GNG%04d",(numcode)/5);break;
		case 4:sprintf(code,"SEG%04d",(numcode)/5);break;
	}

	section = byte4;				//set the section
	makekey();						// set the key
	
	string str;
	getline(fs,str,'|');			// read field-5
	if(fs.fail()) return -1;
	setcname(str.c_str(),str.length());
	getline(fs,str,'|');			// read field-6
	if(fs.fail()) return -1;
	setpname(str.c_str(),str.length());
	getline(fs,str,'|');			// read field-7
	if(fs.fail()) return -1;
	setclink(str.c_str(),str.length());
	getline(fs,str,'|');			// read field-8
	if(fs.fail()) return -1;
	setplink(str.c_str(),str.length());

	return size;				// return number of bytes read
}

int Record::write(ostream& fs)
{
	if(key==0) makekey();			//construct key if not already done
	fs.write((char*)&key,4); 
	fs.write(cname,s5);fs.write("|",1); 
	fs.write(pname,s6);fs.write("|",1);
	fs.write(clink,s7);fs.write("|",1);
	fs.write(plink,s8);fs.write("|",1);
	
	if(fs.good()) return size;		// successfully written size bytes
	else return -1;					// error in writing the record
}

void Record::printkey(ostream& fs)			// print only the key part
{
	fs << "\nYear: "<< START+year;
	switch(term){
	case 0: fs << "\nTerm: Fall"; break;
	case 1: fs << "\nTerm: Winter"; break;
	case 2: fs << "\nTerm: Summer"; break;
	}
	fs << "\nCode: ";
	fs.write(code,7);
	fs << "\nSection: "<< section <<endl;
}

void Record::printall(ostream& fs)		//print the whole record
{
	fs << "\nYear: "<< START+year;
	switch(term){
	case 0: fs << "\nTerm: Fall"; break;
	case 1: fs << "\nTerm: Winter"; break;
	case 2: fs << "\nTerm: Summer"; break;
	}
	fs << "\nCode: ";
	fs.write(code,7);
	fs << "\nSection: "<< section;
	fs << "\nCourse Name: ";
	fs.write(cname,s5);
	fs << "\nInstructor Name: ";
	fs.write(pname,s6);
    fs << "\nCourse Webpage: ";
    fs.write(clink,s7);
	fs << "\nProfessor's Homepage: ";
	fs.write(plink,s8);
	fs << endl;

}