#include "customer.h"
#include "common.h"
#include "menu.h"
#include <fstream>
#include <conio.h>
#include <iomanip>
using namespace std;

customer::customer()
{
	fName="";
	lName="";
	driversLicense="";
	streetAddress="";
	cityStateZip="";
	phone="";
	currentRentals.clear();

}

bool customer::isGuestAccount()
{
	return driversLicense.length() < 1;
}

bool customer::initNewCustomer()
{
	const int NUM_FIELDS=6;
	const int FIELD_WIDTH=20;
	const int MIN_DATA_LENGTH=3;
	const int DATA_WIDTH=SCREEN_WIDTH-FIELD_WIDTH-9;

	string fieldName[NUM_FIELDS] = 
	{	"First Name", 
		"Last Name",
		"Street Address", 
		"City, State, Zip",
		"Phone #",
		"Driver's License #"
	};

	position p;
	char choice=NULL;

	do {
		p.row=2; p.col=3;
		drawBorder(p,SCREEN_WIDTH-9,SCREEN_HEIGHT-9,"Create new customer");

		setColor(BRwhite,BRblack);
		p.col++;
		
		for ( int i=0; i < NUM_FIELDS; i++ )
		{
			p.row++; setScreenPos(p);
			cout << right << setw(FIELD_WIDTH) << fieldName[i];
		}

		p.row=2; p.col=4+FIELD_WIDTH;
		setColor(BRgreen,black);
		for ( int i=0; i < NUM_FIELDS; i++ )
		{
			p.row++; setScreenPos(p);
			string thisFieldData="";
			thisFieldData=standardPrompt(BRgreen,black,DATA_WIDTH);

			// check length
			if ( thisFieldData.length() < MIN_DATA_LENGTH )
			{
				i--; 
				setScreenPos(p);
				p.row--;
				for ( int f=0; f < DATA_WIDTH; f++ ) cout << ' ';
				continue;
			}
			switch ( i )
			{
				case 0:
					fName=thisFieldData;
					break;
				case 1:
					lName=thisFieldData;
					break;
				case 2:
					streetAddress=thisFieldData;
					break;
				case 3:
					cityStateZip=thisFieldData;
					break;
				case 4:
					phone=thisFieldData;
					break;
				case 5:
					driversLicense=thisFieldData;
					break;
			};

		}

		p.row=SCREEN_HEIGHT-4; p.col=(SCREEN_WIDTH/2)-12;
		drawBorder(p,24,1);
		p.row++; p.col++;
		setScreenPos(p);
		setColor(BRyellow,BRblue);

		cout << left << setw(24) << "[D]one, [R]edo, [A]bort";
		choice = toupper(_getch());

		p.row=SCREEN_HEIGHT-4; p.col=(SCREEN_WIDTH/2)-12;
		removeBorder(p,24,1);
		p.row=2; p.col=3;
		removeBorder(p,SCREEN_WIDTH-9,SCREEN_HEIGHT-9);

	} while ( choice == 'R' );

	if ( choice == 'D' )
		return true;
	else
		return false;
}

void customer::editDetails()
{
	const int FIELD_WIDTH=45;
	const int MIN_DATA_LENGTH=3;
	const int DATA_WIDTH=SCREEN_WIDTH-FIELD_WIDTH-9;
	
	position p;

	string oldFile=myFilename;
	string oldDLN=driversLicense;

	// make sure the file exists firsts

	if ( !doesFileExist(myFilename) )
	{
		alert("Customer file cannot be found!");
		return;
	}
	
	char choice=NULL;
	enum choices
	{ FNAME, LNAME, ADDR1, ADDR2, PHONE, DLN, DELETE, EXIT };
	string fieldName[6] = {
		"First Name", "Last Name", "Street Address", "City, State, Zip", "Phone Number", 
		"Driver's License"
	};
	
	p.row=6;	p.col=2;
	menu editMenu("Edit Options");
	editMenu.addChoice(fieldName[0]);
	editMenu.addChoice(fieldName[1]);
	editMenu.addChoice(fieldName[2]);
	editMenu.addChoice(fieldName[3]);
	editMenu.addChoice(fieldName[4]);
	editMenu.addChoice(fieldName[5]);
	editMenu.addChoice("Delete this Customer");
	editMenu.addChoice("Done");
	editMenu.setPosition(p);

	bool deleteFlag=false;

	do {
		// display details as they currently exist
		p.row=6; p.col=25;
		drawBorder(p,FIELD_WIDTH,6,"Edit customer");
		setColor(BRgreen,black);
		p.col++;

		p.row++; setScreenPos(p);	cout << left << setw(FIELD_WIDTH) << "        First Name:"+fName;
		p.row++; setScreenPos(p);	cout << left << setw(FIELD_WIDTH) << "         Last Name:"+lName;
		p.row++; setScreenPos(p);	cout << left << setw(FIELD_WIDTH) << "    Street Address:"+streetAddress;
		p.row++; setScreenPos(p);	cout << left << setw(FIELD_WIDTH) << "  City, State, Zip:"+cityStateZip;
		p.row++; setScreenPos(p);	cout << left << setw(FIELD_WIDTH) << "           Phone #:"+phone;
		p.row++; setScreenPos(p);	cout << left << setw(FIELD_WIDTH) << "Driver's License #:"+driversLicense;
			
		// ask the user which detail to edit
		int choice=editMenu.getUserChoice(EXIT);

		// get the new data
		string thisFieldData;
		if ( choice != EXIT )
		{
			setScreenPos(15,3); setColor(BRgreen,black);
			if ( choice == DELETE )
				cout << left << setw(SCREEN_WIDTH-5) << "Type \"DELETE\" to confirm: ";
			else
				cout << left << setw(SCREEN_WIDTH-5) << "Enter new "+fieldName[choice]+": ";
			setScreenPos(16,3); 
			thisFieldData=standardPrompt(BRyellow,black,DATA_WIDTH);
			setScreenPos(15,3); cout << setw(SCREEN_WIDTH-5) << " ";
			setScreenPos(16,3); cout << setw(SCREEN_WIDTH-5) << " ";

			// replace
			if ( thisFieldData.length() >= MIN_DATA_LENGTH )
			{
				switch ( choice )
				{
					case FNAME:
						fName=thisFieldData;
						break;
					case LNAME:
						lName=thisFieldData;
						break;
					case ADDR1:
						streetAddress=thisFieldData;
						break;
					case ADDR2:
						cityStateZip=thisFieldData;
						break;
					case PHONE:
						phone=thisFieldData;
						break;
					case DLN:
						driversLicense=thisFieldData;
						break;
					case DELETE:
						if ( ucase(thisFieldData) == "DELETE" )
						{
							deleteFlag=!deleteFlag;
							if ( deleteFlag )
								alert("Will delete when you exit this screen.");
							else
								alert("No longer will delete when you exit this screen.");							
						}
				}
			}
		}
		if ( choice == EXIT ) break;	// don't ask me why I need this line. 8(
	} while ( choice != EXIT );

	// construct the new filename (if any) and make sure it's safe
	
	if ( oldDLN != driversLicense )
	{
		if ( safeFilename(driversLicense) ) 
			myFilename="customers\\"+driversLicense;
		else
		{
			alert("That is an invalid driver's license number");
			driversLicense=oldDLN;
		}
	}

	// make sure the new filename doesn't already exist
	if ( oldFile != myFilename )
	{
		if ( doesFileExist(myFilename) )
		{
			alert("That driver's license is already in use!");
			driversLicense=oldDLN;
			myFilename=oldFile;
		}
	}

	if ( oldFile != myFilename || deleteFlag )
	{
		// delete the old file
		string cmd="del \""+oldFile+"\"";
		system(cmd.c_str());
	}

	// save the new file (which may have a different filename now)
	if ( !deleteFlag )
		save();	

	p.row=1; p.col=1;
	removeBorder(p,SCREEN_WIDTH-4,SCREEN_HEIGHT-4);
}

void customer::load(ifstream &inFile, string filename)
{
	myFilename=filename;	// save this for later, when I go to save...

	string strLine;
	string varb, val;
	int pos;

	do {
		getline(inFile,strLine);
		strLine=trim(strLine);
		if ( !inFile.eof() )
		{
			pos=strpos(strLine,"=");
			if ( pos > 0 ) 
			{
				varb=left(strLine,pos);
				varb=lcase(varb);
				val=strLine.substr(pos+1,strLine.length()-pos);
				if ( "license"	== varb ) driversLicense=val;
				if ( "fname"	== varb ) fName=val;
				if ( "lname"	== varb ) lName=val;
				if ( "address1" == varb ) streetAddress=val;
				if ( "address2" == varb ) cityStateZip=val;
				if ( "phone"	== varb ) phone=val;
				if ( "currentrentals" == varb ) currentRentals=split(val);
				if ( "pastrentals" == varb ) pastRentals=split(val);
			}
		} // end if not end of file
	} while ( !inFile.eof() );
}

void customer::save(string filename)
{
	if ( "" == filename && myFilename != "" ) filename=myFilename;	// no filename specified, use the one that I was loaded from
	ofstream outFile;
	outFile.open (filename.c_str());
	if ( !outFile )
	{
		outFile.close();
		alert("Cannot save customer file");
		return;
	}

	// each field will need to be converted to a char array of fixed length
	// so that this record is exactly the size of every other record
	
	outFile	<< "license=" << driversLicense << endl
		    << "fName=" << fName << endl
			<< "lName=" << lName << endl
			<< "address1=" << streetAddress << endl
			<< "address2=" << cityStateZip << endl
			<< "phone=" << phone << endl			
			<< "currentRentals=";
	// save all current rentals
	for ( unsigned int i=0; i < currentRentals.size(); i++ )
	{
		if ( i > 0 ) outFile << ",";
		outFile << currentRentals[i];
	}
	outFile << endl;
	// save all past rentals
	outFile << "pastRentals=";
	for ( unsigned int i=0; i < pastRentals.size(); i++ )
	{
		if ( i > 0 ) outFile << ",";
		outFile << pastRentals[i];
	}
	outFile << endl;
}

string customer::getDriversLicense()
{
	return driversLicense;
}
string customer::getName()
{
	string fullname=fName;
	fullname.append(" ");
	fullname.append(lName);
	return fullname;
}
string customer::getPhone()
{
	return phone;
}
string customer::getFilename()
{
	return myFilename;
}

void customer::display()
{
	// displays basic customer info at the top of the screen

	position topLeft;
	topLeft.row=0; topLeft.col=0;
	unsigned int width=SCREEN_WIDTH-2;
	//drawBorder(topLeft,SCREEN_WIDTH-2,2);
	
	setColor(BRwhite,BRblack);
	setScreenPos(topLeft.row+1,topLeft.col+1);

	if ( driversLicense.length() < 1 )
	{
		// display "guest access"
		cout << "Logged in as guest";
		for ( unsigned int i=18; i < width; i++ ) cout << " ";	// pad out with spaces
	} else {
		// display basic customer info		
		cout << fName << " " << lName;
		for ( unsigned int i=fName.length()+lName.length()+1; i < width; i++ ) cout << " ";	// pad out with spaces

		setScreenPos(topLeft.row+2,topLeft.col+1);
		cout << streetAddress << " " << cityStateZip;
		for ( unsigned int i=streetAddress.length()+cityStateZip.length()+1; i < width; i++ ) cout << " ";	// pad out with spaces

		setScreenPos(topLeft.row+3,topLeft.col+1);
		cout << phone;
		for ( unsigned int i=phone.length(); i < width; i++ ) cout << " ";	// pad out with spaces
	}

	setColor(BRyellow,red);
	setScreenPos(topLeft.row+4,topLeft.col);
	cout << char(199); // ╟
	for ( int i=0; i < SCREEN_WIDTH-2; i++ ) cout << char(196);
	cout << char(182); // ╢


}

bool customer::onCheckoutList(string movieID)
{
	bool result=false;
	for ( unsigned int i=0; i < currentRentals.size() && !result; i++ )
	{
		string currentID=currentRentals[i];
		int pos=strpos(currentID,"-");
		if ( pos > 0 )
			currentID=left(currentID,pos);

		if ( currentID == movieID )
			result=true;
	}

	return result;
}

void customer::checkoutMovie(string movieID)
{
	currentRentals.push_back(movieID);
}

void customer::checkinMovie(string movieID)
{
	vector<string>::iterator i=currentRentals.begin();
	while ( i < currentRentals.end() )
	{
		if ( *i == movieID )
		{
			pastRentals.push_back(movieID);
			currentRentals.erase(i);
			break;
		}
		i++;
	};

}
void customer::checkinByList(forest &theForest)
{
	if ( currentRentals.size() < 1 ) 
	{
		alert("You don't have any movies checked out right now");
		return;
	}

	setStatus("Select a movie to check in and press enter");
	string checkinID;

	char choice;
	enum choices
	{ NEXT_ITEM=80, PREV_ITEM=72, EXIT=27, PGDN=81, PGUP=73, ENTER=13 };
	const unsigned int ITEMS_PER_PAGE=SCREEN_HEIGHT-10;

	int row=5;
	int selectedItem=0;
	int topItem=0;
	setColor(BRyellow,BRred);
	setScreenPos(row,1);
	cout << left << setw(SCREEN_WIDTH-2) << "Select a movie to check in, Press ESC to quit";

	do {
		row=6;
		setScreenPos(row,1);

		movie *selectedMovie;
		int selectedCopyNum=0;

		int lastItem=topItem + ITEMS_PER_PAGE;
		for ( int i=topItem; i <= lastItem; i++ )
		{
			setScreenPos(row,1);	row++;
			if ( i < currentRentals.size() )
			{
				if ( i == selectedItem )
					setColor(BRyellow,BRblue);	// highlight selected item
				else
					setColor(black,BRblack);	// not selected, use normal color
			} else {
				setColor(black,black);			// blank line drawn black on black
			}
			
			if ( i < currentRentals.size() )
			{
				// remove copy # from id
				string thisID=currentRentals[i];
				
				int pos=strpos(thisID,"-");
				if ( pos > 0 ) 
				{
					thisID=left(thisID,pos);
					if ( i == selectedItem ) 
					{	// get the copy number if this is the selected item
						string cnum=currentRentals[i].substr(pos+1,currentRentals[i].length()-pos);
						selectedCopyNum = atoi(cnum.c_str());
					}
				}

				movie::setSortField(SORT_FIELD_ID);
				movie *currentMovie=theForest.trees[SORT_FIELD_ID].getNode(SORT_FIELD_ID,thisID);
				if ( i == selectedItem ) selectedMovie=currentMovie;

				if ( currentMovie != NULL )
					cout << left << setw(SCREEN_WIDTH-2) << currentMovie->getTitle();
				else
					cout << left << setw(SCREEN_WIDTH-2) << "(ERROR) failed to find movie in database";				
			}
			else
				for ( int j=0; j < SCREEN_WIDTH-2; j++ ) cout << " ";	// fill line with space to erase previous entry
		}

		choice=_getch();
		char letter=tolower(choice);

		if ( -32 == choice || 0 == choice ) 
			choice=_getch();

		// handle key presses
		if ( NEXT_ITEM == choice )
		{	// arrow down
			if ( selectedItem < currentRentals.size()-1 )
			{	
				selectedItem++;
				if ( selectedItem > lastItem ) topItem++;	// scroll down
			}
		} else if ( PREV_ITEM == choice ) 
		{	// arrow up
			if ( selectedItem > 0 )
			{
				selectedItem--;
				if ( selectedItem < topItem ) topItem--;	// scroll up
			}
		} else if ( PGDN == choice )
		{	// page down
			int tmp=topItem+ITEMS_PER_PAGE;
			if ( tmp >= currentRentals.size() )	tmp=currentRentals.size()-1;
			selectedItem=topItem=tmp;
		} else if ( PGUP == choice )
		{	// page up
			int tmp=topItem-ITEMS_PER_PAGE;
			if ( tmp < 0 ) tmp=0;
			selectedItem=topItem=tmp;
		} else if ( ENTER == choice )
		{	// check in this movie
			selectedMovie->checkin(selectedCopyNum);
			vector<string>::iterator iter=currentRentals.begin();
			iter+=selectedItem;			
			currentRentals.erase(iter);
			
			selectedItem=topItem=0;	// go back to the top of the list
		}
	} while ( choice != EXIT && currentRentals.size() > 0 );

	setStatus("");

	// clear list
	position topLeft;
	topLeft.row=5;
	topLeft.col=1;
	removeBorder(topLeft,SCREEN_WIDTH-4,SCREEN_HEIGHT-8);
}

/* ********** customer related functions that aren't part of the class ********** */

customer* customerLogin()
{

	customer *theCustomer=NULL;

	position topLeft;
	topLeft.row=SCREEN_HEIGHT/2;
	topLeft.col=(SCREEN_WIDTH/2)-13;

	drawBorder(topLeft,25,1,"Enter Driver's License #");
	setScreenPos(topLeft.row+1,topLeft.col+1);
	setColor(BRgreen,black);
	string tryDLN=standardPrompt(BRgreen,black,25);
	removeBorder(topLeft,26,1);

	if ( safeFilename(tryDLN) )
	{
		string fileName="customers\\";
		fileName.append(tryDLN);
		ifstream inFile;
		inFile.open(fileName.c_str());
		if ( inFile )
		{
			theCustomer=new customer();
			theCustomer->load(inFile,fileName);
			//theCustomer->display();
		} else {
			alert ("Not found, please ask the manager to set you up.");
		}
		inFile.close();
	} else {
		alert("Invalid entry");
	}

	return theCustomer;
}

void customerMenu(customer *theCustomer, forest &theForest)
{
	{
		string status="Welcome";
		if ( !theCustomer->isGuestAccount() )
		{
			status.append(", ");
			status.append(theCustomer->getName());
		}
		setStatus(status);
	}

	enum choices
	{ MOVIES, CHECKIN, LOGOUT };

	menu custMenu("Customer Menu");
	custMenu.addChoice("Movies Database");
	custMenu.addChoice("Check in a Movie");
	custMenu.addChoice("Logout");

	int userChoice;
	do {
		userChoice=custMenu.getUserChoice(LOGOUT);
		if ( MOVIES == userChoice )
		{
			if ( theCustomer->isGuestAccount() )
				listMovies(theForest, NULL);	// browse as guest without the option to checkout
			else
				listMovies(theForest, theCustomer);	// browse as customer with option to checkout
		} else if ( CHECKIN == userChoice )
		{
			// check in
			if ( theCustomer->isGuestAccount() )
				alert("Guest account cannot do that");
			else
			{
				theCustomer->checkinByList(theForest);
			}
		}
	} while ( userChoice != LOGOUT );

	// user is logging out, remove the user info from the top of the screen
	position topLeft;
	topLeft.row=1;
	topLeft.col=1;
	setColor(black,black);

	while ( topLeft.row < 5 )
	{
		setScreenPos(topLeft);
		for ( int c=0; c < SCREEN_WIDTH-2; c++ ) cout << " ";
		topLeft.row++;
	}

	setColor(BRyellow,red);
	setScreenPos(topLeft.row-1, 0);
	cout << char(186); // ║
	setScreenPos(topLeft.row-1,SCREEN_WIDTH-1);
	cout << char(186); // ║

}