/*
GROUP MINI PROJECT- HOTEL BOOKING SYSTEM
GROUP MEMBERS:
 1. GOH JO EY        A19EC0047
 2. ONG YIN REN      A19EC0204
 3. CHIAM WOOI CHIN  A19EC0034
 4. NG JING ER       A19EC0115

*/

#include <iostream>
#include <iomanip>
#include <string>
#include <conio.h>
#include <stdlib.h>
#include <cmath>
#include <cctype>

using namespace std;

class billNode{
	public:
	int roomNum;
	float price;
	string ic;
	string name;
	double total;
	string DateIn;
	string DateOut;
	int days;
	billNode *next;
};


class billQueue{
	billNode *frontPtr,*backPtr;
	public:
		billQueue(){
			backPtr=NULL;
			frontPtr=NULL;
		}
		~billQueue(){
			billNode *temp = frontPtr;
			while (temp){
			frontPtr = temp->next;
			delete temp; 
			temp=frontPtr;
			}
		}
		bool isEmpty(){
			return (backPtr == NULL && frontPtr == NULL);
		}
		
		//implementation of queue 
		void enQueue(int rn,float p,string ic,string n,string in,string out,int d){
			billNode *temp=new billNode;
			if (backPtr == NULL) {
    			temp->next = NULL;
    			temp->roomNum = rn;
    			temp->price = p;
    			temp->ic = ic;
    			temp->name= n;
    			temp->DateIn = in;
				temp->DateOut = out;
				temp->days=d;
				frontPtr = backPtr = temp;
   			}   
			else { 
      			backPtr->next = temp;
      			temp->roomNum = rn;
    			temp->price = p;
    			temp->ic = ic;
    			temp->name= n;
    			temp->DateIn = in;
				temp->DateOut = out;
				temp->days=d;
      			temp->next = NULL;
      			backPtr = temp;
   			}
		}
		void displayInvoice(billNode *temp){
			if(temp->days<=1){
				temp->days==1;
			}
			temp->total=temp->price*1.06*(temp->days*1.0);
			cout<<"\n\n======	BOOKING NEED TO CONFIRM		======";
			cout<<"\nCUSTOMER NAME\t: "<<temp->name<<endl;
			cout<<"CUSTOMER IC\t: "<<temp->ic<<endl;
			cout<<"BOOKING ROOM NO\t: "<<temp->roomNum<<endl;
			cout<<"DATE CHECK IN\t: "<<temp->DateIn<<endl;
			cout<<"DATE CHECK OUT\t: "<<temp->DateOut<<endl;
			cout<<"NUMBER OF DAYS\t: "<<temp->days<<endl;
			cout<<"PRICE PER NIGHT\t: RM"<<temp->price<<endl;
			cout<<"TOTAL(AFTER SST): RM"<<temp->total<<endl;
		}
		
		//implementation of queue 
		string deQueue(){
			billNode *temp=new billNode;
			temp = frontPtr;
 			if (frontPtr == NULL) {
    			cout<<"NO PENDING BOOKING NEED TO BE CONFIRMED"<<endl;
				return "NULL";
  			}
   			else if (temp->next != NULL) {
				
				int choice;
				displayInvoice(temp);	
				do{	
				cout<<"DO YOU WANT TO CONFIRM THIS BOOKING? (0-PENDING, 1-CONFIRMED, 2-CANCELLED) : ";
				cin>>choice;
					if(choice==1){
						temp = temp->next;
    					frontPtr = temp;
    					return "BOOKED-CONFIRMED";
    				}
    				else if(choice==0){
    				temp = temp->next;
    				frontPtr = temp;
					return "BOOKED-PENDING";
					}
					else if(choice==2){
					temp = temp->next;
    				frontPtr = temp;
					return "CANCELLED";
					}
				}while(choice<0&&choice>2);
				
   				 
   			}
			else {
   				int choice;
   				displayInvoice(temp);
   				do{			   
   				cout<<"\n\nDO YOU WANT TO CONFIRM THIS BOOKING? (0-PENDING, 1-CONFIRMED, 2-CANCELLED) : ";
   				cin>>choice;
   					if(choice==1){
   					temp = temp->next;
    				frontPtr = temp;
    				return "BOOKED-CONFIRMED";
    				}
    				else if(choice==0){
    				return "BOOKED-PENDING";
					}
					else if(choice==2){
					return "CANCELLED";
					}
				}while(choice<0&&choice>2);
			}
		
		}
		billNode* getFrontRN(){
			billNode *t=new billNode;
				if(frontPtr!=NULL){
				t=frontPtr;
				}
			return t;
		}
};

class custNode{
	public:
	string custName;
	string custPhone;
	string ic;
	string DateIn;
	string DateOut;
	int roomNum;
	custNode *next;
};

class customer{
	custNode *head;
	public:
		customer(){head=NULL;}
			
		void sortedCustIn(string n, string p, string ic, string in,string out,int rn){
			int currIndex=0;
			custNode *currNode=head;
			custNode *prevNode=NULL;
				while(currNode && n > currNode->custName){
					prevNode=currNode;
					currNode=currNode->next;
					currIndex++;	
				}	
			custNode *newNode=new custNode;
			newNode->custName=n;
			newNode->custPhone=p;
			newNode->ic=ic;
			newNode->DateIn=in;
			newNode->DateOut=out;
			newNode->roomNum=rn;
				if (currIndex==0){
					newNode->next=head;
					head=newNode;
				}
				else{
				newNode->next=prevNode->next;
				prevNode->next=newNode;
				}	
		}
		void deleteCust(string ic,int rn){ 
			custNode* prevNode = NULL;
			custNode* currNode = head;
			int currIndex = 1;
		
			string IC=currNode->ic.substr(0,12);
			int y = atoi(IC.c_str());
			int x= atoi(ic.c_str());
	
			while ((currNode && x!= y)||(currNode && currNode->roomNum!=rn)) {
				prevNode = currNode;
				currNode = currNode->next;
				currIndex++;
			}
			
			if(x==y){
				if (currNode) {
					if (prevNode) {
						prevNode->next = currNode->next;
						delete currNode;
					}
					else {
						head = currNode->next;
						delete currNode;
					}
				}
			cout<<"ROOM BOOKED("<<rn<<") UNDER CUSTOMER WITH IC "<<ic<<" HAS BEEN DELETED "<<endl;
			}
	        else{
	        cout<<"BOOKING RECORD OF "<<rn<<" UNDER CUSTOMER WITH IC "<<ic<<" ICANNOT BE FOUND"<<endl;	
			}
		}
			
		bool findCust(string _ic){ 
			custNode* currNode = head;
			int currIndex = 1;
			string IC=currNode->ic.substr(0,13);
			int y = atoi(IC.c_str());
			int x= atoi(_ic.c_str());
			if (x==y)
				return true;
			else
				return false;
		}
		
		void displayCustRoom(){ 
			int num = 0; 
			custNode* currNode = head; 
			cout<<"\n\n======================================    BOOKING IN THE HOTEL    ======================================"<<endl;
			cout<<"--------------------------------------------------------------------------------------------------------"<<endl;
			cout<<left<<setw(40) <<"NAME"<<setw(11)<<"ROOM NO."<<setw(15)<<"PHONE"<<setw(20)<<"IC"<<setw(12)<<"DATE IN"<<setw(12)<<"DATE OUT"<<endl;
			
			while (currNode != NULL){ 
				cout <<left<<setw(40)<<currNode->custName
					 <<setw(11)<< left<<currNode->roomNum
					 <<setw(15)<< left<<currNode->custPhone
					 <<setw(20)<< left<<currNode->ic
					 <<setw(12)<< left<<currNode->DateIn
					 <<setw(12)<< left<<currNode->DateOut
					 << endl; 
				currNode = currNode->next; 
				num++; 
			} 
			cout << "\nNUMBER OF ROOM IN THE HOTEL: " << num << endl<<endl<<endl;
		}
		
};

class roomNode{
	public:
	int floorNo;
	int roomNum;
	int roomtype;
	float price;
	int status;
	roomNode *next;
	roomNode *prev;
};

string rt(int rt){
	if(rt==1){
		return "SINGLE";
	}
	else if(rt==2){
		return "DOUBLE";
	}
	else if(rt==3){
		return "FAMILY";
	}
	else if(rt==4){
		return "PREMIUM";
	}
	else{
		return "DEFAULT";
	}
}

string status(int status){
	if(status==1){
		return "BOOKED-PENDING";
	}
	else if(status==2){
		return "BOOKED-CONFIRMED";
	}
	else if(status==0){
		return "AVAILABLE";
	}
	else{
		return "DEFAULT";
	}
}

class room{
	private:
		roomNode *head;
		
	public:
		room(){
			head=NULL;
		}
		
		void insertSortedRoom(int roomNum){
			int currIndex=0;
			roomNode *currNode=head;
			roomNode *prevNode=NULL;
				while(currNode && roomNum > currNode->roomNum){
					prevNode=currNode;
					currNode=currNode->next;
					currIndex++;	
				}	
			roomNode *newNode=new roomNode;
			newNode->roomNum=roomNum;
			newNode->floorNo=roomNum/1000;
			newNode->roomtype=(roomNum-(roomNum/1000*1000))/100;
			newNode->price=setprice(newNode);
			newNode->status=0;
			if (currIndex==0){
				newNode->next=head;
				head=newNode;
			}
			else{
				newNode->next=prevNode->next;
				prevNode->next=newNode;
			}
		}
		float setprice(roomNode *n){
			float p=0;
			roomNode *newNode=new roomNode;
			newNode=n;
			if(newNode->roomtype==1){
				p+=80.00;
			}
			else if(newNode->roomtype==2){
				p+=120.00;
			}
			else if(newNode->roomtype==3){
				p+=150.00;
			}
			else if(newNode->roomtype==4){
				p+=200.00;
			}
			else{
				p=0.00;
			}
			p+=(newNode->floorNo*10.00);
			return p;
		}
		
		void deleteRoom(int rn){
			roomNode* prevNode = NULL;
			roomNode* currNode = head;
			int currIndex = 1;
			while (currNode && currNode->roomNum != rn) {
				prevNode = currNode;
				currNode = currNode->next;
				currIndex++;
			}
			if (currNode) {
			if (prevNode) {
				prevNode->next = currNode->next;
				delete currNode;
			}
			else {
				head = currNode->next;
				delete currNode;
			}
			cout<<"YOU SUCCESSFULLY DELETE THE ROOM WITH NUMBER :"<<rn<<endl;
	        }
	        else{
	        cout<<"ROOM NUMBER ("<<rn<<") DOES NOT EXIST."<<endl;	
			}
		}
		bool bookRoom(int rn){
			roomNode *newNode=new roomNode;
			newNode=findRoom(rn);
			if(!newNode){
				cout<<"ROOM NUMBER "<<rn<<" CANNOT BE FOUND\n"<<endl;
				return false;
			}
			else{
				if(newNode->status==0){
					newNode->status=1;
					cout<<"ROOM NUMBER "<<rn<<" IS SUCCESSFULLY BOOKED\n\n"<<endl;
					return true;
				}
				else{
					cout<<"ROOM NUMBER "<<rn<<" IS NOT AVAILABLE\n\n"<<endl;
					return false;
				}
			}
		} 
		
		bool cancelRoom(int rn){
			roomNode *newNode=new roomNode;
			newNode=findRoom(rn);
			if(!newNode){
				cout<<"ROOM NUMBER "<<rn<<" CANNOT BE FOUND"<<endl;
				return false;
			}
			else{
				if(newNode->status==1){
					newNode->status=0;
					cout<<"BOOKING ROOM WITH NUMBER"<<rn<<" IS SUCCESSFULLY CANCELLED"<<endl;
					return true;
				}
				else{
					cout<<"BOOKING ROOM NUMBER ("<<rn<<") CANNOT BE FOUND"<<endl;
					cout<<"UNABLE TO MAKE CANCELLATION"<<endl;
					return false;
				}
			}
	};
		
		bool findBookRoom(int rn){
			roomNode *newNode=new roomNode;
			newNode=findRoom(rn);
			if(!newNode){
				return false;
			}
			else{
				if(newNode->status==1){
					return true;
				}
				else{
					return false;
				}
			}
		}

		roomNode* findRoom(int rn){			
			roomNode* currNode = head;
			int currIndex = 1;
			while (currNode && currNode->roomNum != rn) {
			currNode = currNode->next;
			currIndex++;
			}
			if (currNode)
				return currNode;
			else
			return 0;
		}
		
		void displayRoom(){
			int num = 0; 
			roomNode* currNode = head; 
			cout<<"====================    ROOM IN THE HOTEL    ===================="<<endl;
			cout<<"-----------------------------------------------------------------"<<endl;
			cout<<"FLOOR\tROOM NO.\tROOM TYPE\tPRICE\tSTATUS"<<endl;
			
			
			while (currNode != NULL){ 
				cout <<currNode->floorNo<<"\t"
					 <<currNode->roomNum <<"\t\t"
					 <<rt(currNode->roomtype)<<"\t\t"
					 <<currNode->price<<"\t"
					 <<status(currNode->status)<<"\t"
					 << endl; 
				currNode = currNode->next; 
				num++; 
			} 
			cout << "\nNUMBER OF ROOM IN THE HOTEL: " << num << endl<<endl<<endl;
		}
};

int getDays(string date) {
        int year = atoi(date.substr(0, 4).c_str());
        int month = atoi(date.substr(4, 2).c_str());
        int day = atoi(date.substr(6, 2).c_str());
        int ans = 0;
        for (int i = 1900; i < year; ++ i) {
            if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
                ans += 366;
            } else {
                ans += 365;
            }
        }
        for (int i = 1; i < month; ++ i) {
            switch(i) {
                case 1: ans += 31; break;
                case 2: ans += (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) ? 29 : 28; break;
                case 3: ans += 31; break;
                case 4: ans += 30; break;
                case 5: ans += 31; break;
                case 6: ans += 30; break;
                case 7: ans += 31; break;
                case 8: ans += 31; break;
                case 9: ans += 30; break;
                case 10: ans += 31; break;
                case 11: ans += 30; break;
                case 12: ans += 31; break;
            }
        }
        return ans += day - 1;
    }

int daysBetweenDates(string date1, string date2) {
        return abs(getDays(date1) - getDays(date2));
}

int main(){
	
	//CREATE HOTEL ROOM 
	room h;
	customer cn;
	billQueue bq;
	int choice;
	
	//ADD DEFAULT ROOM
	int defaultroom[]={1101,1202,1303,1102,1103,1104,2201,2202,2203,3301,3302,3303,3304,4401,4402} ;
	for(int x=0;x<15;x++){
		h.insertSortedRoom(defaultroom[x]);
	}

	do{
		system("CLS");
		cout<<"=============		HOTEL BOOKING SYSTEM		============="<<endl;
		cout<<"\t\t\tLOGIN AS"<<endl;
		cout<<"\t\t\t1. ADMIN\n\t\t\t2. CUSTOMER \n\t\t\t3. EXIT\n"<<endl;
		cout<<"CHOICE : ";
		cin>>choice;
		switch(choice){
			case 1:{
				int ch1;
				int rn;
				int cont1;
				do{
				system("CLS");
				cout<<"=============	ADMIN MENU	============="<<endl;
				cout<<"\t1. ADD ROOM\n\t2. DELETE ROOM\n\t3. DISPLAY ROOM\n\t4. CHANGE PRICE\n\t5. CHECK CUSTOMER BOOKING LIST\n\t6. REVIEW AND CONFIRM PENDING BOOKING\n\t7. BACK TO MAIN MENU\n"<<endl;
				cout<<"CHOICE : ";
				cin>>ch1;
				switch(ch1){
				case 1:
					cont1=1;
					do{
					cout<<"\nENTER THE ROOM NUMBER YOU WANT TO ADD : ";
					cin>>rn;
					if(!h.findRoom(rn)){
						h.insertSortedRoom(rn);
						cout<<"YOU SUCCESSFULLY ADD ROOM NUMBER ("<<rn<<") TO THE LIST"<<endl;
					}
					else{
						cout<<"ROOM NUMBERED "<<rn<<" EXISTED.  ENTER OTHER ROOM NUMBER."<<endl;
					}
					cout<<"DO YOU WANT TO CONTINUE TO ADD MORE ROOM ( 1-YES, 0-NO ) :";
					cin>>cont1;
					}while(cont1!=0);
					break;
				case 2:
					cont1=1;
					do{
					cout<<"\nENTER THE ROOM NUMBER YOU WANT TO DELETE : ";
					cin>>rn;
					if(h.findRoom(rn)){
						h.deleteRoom(rn);
					}
					else{
						cout<<"ROOM CANNOT BE FOUND! ENTER OTHER ROOM NUMBER."<<endl;
					}
					cout<<"DO YOU WANT TO CONTINUE TO DELETE MORE ROOM( 1-YES, 0-NO ) : ";
					cin>>cont1;
					}while(cont1!=0);
					break;
				case 3:
					h.displayRoom();
					break;
				case 4:
					cont1=1;
					do{
					cout<<"\nENTER THE ROOM NUMBER THAT YOU WANT CHANGE PRICE: "<<endl;
					cout<<"ROOM NUMBER        : ";
					cin>>rn;
					if(h.findRoom(rn)){
						float p;
						cout<<"CHANGE TO PRICE RM : ";
						cin>>p;
						roomNode *newNode=h.findRoom(rn);
						newNode->price=p;
						cout<<"YOU SUCCESSFULLY CHANGE THE PRICE OF ROOM NUMBER "<<rn<<" TO PRICE RM "<<p<<endl<<endl;
					}
					else{
						cout<<"ROOM NUMBER ("<<rn<<") CANNOT BE FOUND. ENTER OTHER ROOM NUMBER."<<endl<<endl;
					}
					cout<<"DO YOU WANT TO CONTINUE TO CHANGE PRICE OF THE OTHER ROOMS ( 1-YES, 0-NO ) :";
					cin>>cont1;
					}while(cont1!=0);
					break;
				case 5:
					cn.displayCustRoom();
					break;
				case 6:
					cont1=1;
					
					cout<<"\n\n======     START TO REVIEW BOOKING INFORMATION     ======\n";
					do{
					
					billNode* rno=new billNode;
					rno=bq.getFrontRN();
					string con=bq.deQueue();
					roomNode *t=new roomNode;
					t=h.findRoom(rno->roomNum);
					if(con=="BOOKED & CONFIRMED"){
						t->status=2;
						
						break;
					}
					else if(con=="CANCELLED"){
						t->status=0;
						break;
					}
					else if(con=="BOOKED & PENDING"){
						t->status=1;
						bq.enQueue(rno->roomNum,rno->price,rno->ic,rno->name,rno->DateIn,rno->DateOut,rno->days);
						break;	
					}
					else {}
					
					cout<<"DO YOU WANT TO CONTINUE TO REVIEW ( 1-YES, 0-NO ) :";
					cin>>cont1;
						
				}while(cont1!=0);	
					break;
				case 7:
					break;
				default:
					cout<<"INVALID CHOICE."<<endl;
					break;
			}
				system("pause");
				getch();	
			
			}while(ch1!=7);
			break;
			}
			break;
			
			case 2:{
				int ch2;
				int rn,rn2;
				int cont2;
				do{
				system("CLS");
				cout<<"=============	CUSTOMER MENU	============="<<endl;
				cout<<"\t1. DISPLAY ROOM\n\t2. BOOK A ROOM\n\t3. CANCEL ROOM\n\t4. BACK TO MAIN MENU"<<endl;
				cout<<"CHOICE : ";
				cin>>ch2;
				switch(ch2){
				case 1:
					h.displayRoom();
					break;
				case 2:
					cont2=1;
					do{
					cout<<"\nENTER THE ROOM NUMBER YOU WANT TO BOOK : ";
					cin>>rn;
					bool book=h.bookRoom(rn);
					if(book){
					string n, p, ic, in, out;
					int din,min,yin,dout,mout,yout;
					char s;
					cout<<"======== YOUR PERSONAL DETAILS ========"<<endl;
					cout<<"ENTER YOUR NAME      : ";
					cin.ignore();
					getline(cin,n);
					cout<<"ENTER YOUR PHONE NO  : ";
					getline(cin,p);
					cout<<"ENTER YOUR IC (xxxxxx-xx-xxxx): ";
					getline(cin,ic);
					cout<<"DATE IN (YYYYMMDD)   : ";
					getline(cin,in);
					cout<<"DATE OUT (YYYYMMDD)  : ";
					getline(cin,out);
					int days=daysBetweenDates(in,out);
					cn.sortedCustIn(n,p,ic,in,out,rn);
					cout<<"\n----------------------------------\n";
					cout<<"\nPLEASE PROCEEED TO BILL AT COUNTER\n";
					cout<<"\n----------------------------------\n";
					roomNode *t=new roomNode;
					t=h.findRoom(rn);
					bq.enQueue(rn,t->price,ic,n,in,out,days);
					}
					cout<<"DO YOU WANT TO CONTINUE TO BOOK ROOM( 1-YES, 0-NO ) :";
					cin>>cont2;
					}while(cont2!=0);
					break;
					
				case 3:
					cont2=1;
					do{
					string ic2;
					int rn2=0;
					cout<<"\nENTER THE ROOM NUMBER YOU WANT TO CANCEL : ";
					cin>>rn2;
					cout<<"ENTER YOUR IC TO MAKE CANCELLATION (xxxxxx-xx-xxxx): ";
					cin.ignore();
					getline(cin,ic2);
					
					bool targetRoom=h.findBookRoom(rn2);
					if(targetRoom){
						bool targetCust=cn.findCust(ic2);
						if(targetCust){
							h.cancelRoom(rn2);
							cn.deleteCust(ic2,rn2);
						}
						else{
						cout<<"\nRECORD CANNOT BE FOUND\nUNABLE TO MAKE CANCELLATION"<<endl;
						}
					}
					else{
						cout<<"RECORD CANNOT BE FOUND\nUNABLE TO MAKE CANCELLATION"<<endl;
					}
					
					cout<<"DO YOU WANT TO CONTINUE TO CANCEL ROOM ( 1-YES, 0-NO ) : ";
					cin>>cont2;
					}while(cont2!=0);
					break;
				case 4:
					break;
				default:
					cout<<"INVALID CHOICE."<<endl;
					break;
			}
				system("pause");
				getch();
				
			}while(ch2!=4);
				break;
			}
			case 3: 
				cout<<"THANK YOU! BYE BYE."<<endl;
				exit(0);
			default:
				cout<<"INVALID CHOICE."<<endl;
				break;	
		}
		
	getch();
	}while (choice!=3);
	
	return 0;
}

