#include "common.h"
#include "menu.h"
#include "fstream"
using namespace std;
#include "manager.h"
#include "customer.h"
#include <algorithm>

void loadMovies(forest &theForest);
int bSearch(vector<movie*> &, string );
void checkinMovie(forest &theForest);
void checkinMovie(forest &theForest, string movieID);

int main()
{

	sysConfig *cfg=new sysConfig();	// load system configuration

	// the forest contains multiple trees which store pointers to movies, each tree sorted by a different field
	forest theForest;	
	loadMovies(theForest);

	position topLeft={0,0};
	drawBorder(topLeft,SCREEN_WIDTH-2,SCREEN_HEIGHT-1);

	enum choices
	{ CUSTOMER, GUEST, CHECKIN, MANAGER };

	menu mnuLogin("Login Menu");
	mnuLogin.addChoice("Customer Login");
	mnuLogin.addChoice("Guest Login (browse only)");
	mnuLogin.addChoice("Check in a Movie");
	mnuLogin.addChoice("Manager Login");
	int loginAs;

	do {
		loginAs=mnuLogin.getUserChoice();
		setStatus("");

		if ( CUSTOMER == loginAs )
		{	// customer login
			customer *theCustomer=customerLogin();
			if ( theCustomer != NULL )
			{
				// login successful
				theCustomer->display();
				customerMenu(theCustomer, theForest);
				// customer has finsihed her session, save
				theCustomer->save();
			}
			delete theCustomer;
		} else if ( GUEST == loginAs )
		{	// guest login (browse only)
			customer *guest=new customer();
			//guest->display();
			//customerMenu(guest, theForest);
			listMovies(theForest, guest);
			delete guest;
		} else if ( CHECKIN == loginAs )
		{	// check in a movie without logging in
			checkinMovie(theForest);			
		} else if ( MANAGER == loginAs )
		{	// manager login
			if ( managerLogin(cfg) ) managerMenu(cfg, theForest);
		}
		setStatus("Welcome, please login or select Guest to browse inventory.");
	} while ( !cfg->getShutdownFlag() );

	delete cfg;

	return 0;
} // end main function

void loadMovies(forest &theForest)
{
	// loads movies from file into vector
	// empty the vector first (just in case)
	movie::setForestPointer(&theForest);

	ifstream inFile;
	setStatus("Loading movies...");

	inFile.open (MOVIES_FILE);
	int moviesCount=0;

	if ( inFile )
	{
		string strLine;
		do {
			getline(inFile,strLine);
			if ( !inFile.eof() )
			{
				strLine=trim(strLine);
				if ( "<movie>" == lcase(strLine) )
				{
					// found the start of a new movie
					moviesCount++;
					movie *tmpMovie = new movie();
					tmpMovie->load(inFile);
					theForest.addMovie(tmpMovie);
				}
			}
		} while ( !inFile.eof() );
		
		setStatus("Done loading "+string(numToString(moviesCount))+" movies.");
	} else {
		alert("Cannot open movies database file");
	}
	inFile.close();

}
 
void listMovies(forest &theForest, customer *theCustomer, bool managerAccess)
{
	const unsigned int ITEMS_PER_PAGE=SCREEN_HEIGHT-10;
	char choice;
	enum choices
	{ NEXT_ITEM=80, PREV_ITEM=72, EXIT=27, F1=59, PGDN=81, PGUP=73, ENTER=13, BACKSPACE=8, DEL=83 };

	setStatus("To search by title, just start typing!");

	int sortField=SORT_FIELD_TITLE;	
	
	int topItem=0;			// the item that will appear at the top of the list
	int selectedItem=0;	
	string searchTerm;

	bool getList=true;
	vector<movie*> sortedList;

	do 
	{
		if ( getList )
		{
			// get the sorted list from the tree
			
			if ( sortField >= SORT_FIELD_STOCK && sortField <= SORT_FIELD_DATERELEASED )
			{
				// decending order
				sortedList=theForest.trees[sortField].getSortedList(true);
			} else {
				// ascending order
				sortedList=theForest.trees[sortField].getSortedList();
			}
			getList=false;
		}

		// display header
		int row=5;
		string secondField="Genre";
		if ( sortField != SORT_FIELD_GENRE && sortField != SORT_FIELD_TITLE )
			secondField=SORT_FIELD_NAME[sortField];
		setColor(BRyellow,red);
		setScreenPos(row+1,1);
		cout << left << setw(60) << "Title";
		cout << right << setw(SCREEN_WIDTH-62) << secondField;
		setScreenPos(row,1); setColor(BRgreen,black);
		cout << right << setw(SCREEN_WIDTH-2) << "[Enter] Select Movie, [ESC] Quit, [F1] Change Sort Order";

		row=7;
		int lastItem=topItem + ITEMS_PER_PAGE;

		for ( int i=topItem; i <= lastItem; i++ )
		{
			setScreenPos(row,1);	row++;
			if ( i < sortedList.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 < sortedList.size() )
				sortedList[i]->displayList(sortField);	// list this movie
			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 ( searchTerm.length() > 0 ) { searchTerm.clear(); setStatus(""); }
			if ( selectedItem < sortedList.size()-1 )
			{	
				selectedItem++;
				if ( selectedItem > lastItem ) topItem++;	// scroll down
			}
		} else if ( PREV_ITEM == choice ) 
		{	// arrow up
			if ( searchTerm.length() > 0 ) { searchTerm.clear(); setStatus(""); }
			if ( selectedItem > 0 )
			{
				selectedItem--;
				if ( selectedItem < topItem ) topItem--;	// scroll up
			}
		} else if ( PGDN == choice )
		{	// page down
			if ( searchTerm.length() > 0 ) { searchTerm.clear(); setStatus(""); }
			int tmp=topItem+ITEMS_PER_PAGE;
			if ( tmp >= sortedList.size() )	tmp=sortedList.size()-1;
			selectedItem=topItem=tmp;
		} else if ( PGUP == choice )
		{	// page up
			if ( searchTerm.length() > 0 ) { searchTerm.clear(); setStatus(""); }
			int tmp=topItem-ITEMS_PER_PAGE;
			if ( tmp < 0 ) tmp=0;
			selectedItem=topItem=tmp;
		} else if ( F1 == choice )
		{	// changed sort order
			if ( searchTerm.length() > 0 ) { searchTerm.clear(); setStatus(""); }
			sortField++;
			if ( sortField >= NUM_SORT_FIELDS ) sortField=0;
			getList=true;	// flag that the sorted list needs to be rebuilt
			topItem=0;	selectedItem=0;
			setStatus("Sorted by "+SORT_FIELD_NAME[sortField]);
		} else if ( ENTER == choice )
		{	// view movie details
			if ( searchTerm.length() > 0 ) { searchTerm.clear(); setStatus(""); }
			sortedList[selectedItem]->displayFull(theCustomer, managerAccess);
		} else if ( (letter >= 'a' && letter <='z') || letter == ' ' )
		{	// add the letter (or space) to the search term
			searchTerm.append(1,letter);
		} else if ( BACKSPACE == choice && searchTerm.length() > 0 )
		{	// backspace remove the last letter from the search term
			searchTerm=left(searchTerm,searchTerm.length()-1);
			if ( searchTerm.length() == 0 ) setStatus("To search by title, just start typing!");
		} else if ( DEL == choice && managerAccess )
		{
			menu ask("Delete this movie, Are you sure?!");
			ask.addChoice("No                                 ");
			ask.addChoice("Yes                                ");
			int answer=ask.getUserChoice(0);
			if ( 1 == answer )
			{				
				theForest.deleteMovie( sortedList[selectedItem] );
				getList=true;	// flag that the sorted list needs to be rebuilt
			}
		}
		
		// search for a movie by title if a search term has been entered
		if ( searchTerm.length() > 0 )
		{
			if ( sortField != SORT_FIELD_TITLE )
			{	// force back to sorting by title
				sortField=SORT_FIELD_TITLE;
				getList=true;	// flag that the sorted list needs to be rebuilt
				topItem=selectedItem=0;
			}
			setStatus ("Search: "+searchTerm);
			int searchResult=bSearch(sortedList,searchTerm);
			if ( searchResult >= 0 && searchResult < sortedList.size() )
				topItem=selectedItem=searchResult;
		} 

	} while ( choice != EXIT );

	setStatus("");

	// clear list
	position topLeft;
	topLeft.row=5;
	topLeft.col=1;
	removeBorder(topLeft,SCREEN_WIDTH-4,SCREEN_HEIGHT-8);

} // end listMovies function

int bSearch(vector<movie*> &sortedList, string searchTerm)
{
	// binary searches sortedList for item matching searchTerm and returns the index of that item
	// only works on titles

	int result=-1;

	int low=0;
	int high=sortedList.size()-1;

	bool found=false;
	searchTerm=lcase(searchTerm);		// non case-senstitive search

	// remove 'the ' if it exists at the front
	if ( left(searchTerm,4) == "the " ) searchTerm=searchTerm.substr(4,searchTerm.length()-4);

	while ( !found && low <= high )
	{
		int mid=(low+high)/2;
		string thisItem=sortedList[mid]->getTitle();
		thisItem=lcase(thisItem);
		if ( thisItem.length() > searchTerm.length() ) thisItem=left(thisItem,searchTerm.length());
		if ( thisItem == searchTerm )
		{
			found=true;
			result=mid;
		}
		else if ( thisItem < searchTerm  )
			if ( low == mid ) low=mid+1; else low=mid;
		else if ( thisItem > searchTerm  )
			if ( high == mid ) high=mid-1; else high=mid;
	}

	return result;
}
void checkinMovie(forest &theForest)
{
	string movieID;

	position topLeft;
	topLeft.row=SCREEN_HEIGHT/2;
	topLeft.col=(SCREEN_WIDTH/2)-13;

	drawBorder(topLeft,25,1,"Enter Movie ID#: ");
	setScreenPos(topLeft.row+1,topLeft.col+1);
	setColor(BRgreen,black);
	movieID=standardPrompt(BRgreen,black,25);
	removeBorder(topLeft,26,1);

	if ( movieID.length() > 0 )
		checkinMovie(theForest,movieID);

}
void checkinMovie(forest &theForest, string movieID)
{
	// find the movie
	string id;
	int copyNum;

	{ 
		int p=strpos(movieID,"-");
		if ( p > 0 )
		{
			id=left(movieID,p);
			string temp;
			temp=movieID.substr(p+1,movieID.length()-p);
			copyNum=atoi(temp.c_str());
		} else {
			alert("Couldn't locate the movie by it's ID number");
			return;
		}
	}

	movie *theMovie = theForest.trees[SORT_FIELD_ID].getNode(SORT_FIELD_ID,id);
	if ( theMovie == NULL )
		alert("Couldn't locate the movie in the database.");
	else
	{
		string customerID;
		customerID = theMovie->checkin(copyNum);
		customer *theCustomer =  new customer();
		string filename="customers\\";
		filename.append(customerID);
		ifstream inFile;
		inFile.open(filename.c_str());
		if ( inFile )
		{
			theCustomer->load(inFile,filename);
			theCustomer->checkinMovie(movieID);
			theCustomer->save();
			alert(theMovie->getTitle()+" Checked in ok",BRyellow,blue,"Checkin");
		} else {
			alert("Movie checked in, but couldn't locate the customer");
		}
		delete theCustomer;
		inFile.close();
	}

}