#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;

struct Row {
	vector<int> seats;
	int saloonnum,rownum;
	int numberofseats;
};

struct ListNode
	{
		int resnumber,saloonno,rowno,startingseat,numberofseats;
		string name;
		ListNode *next;
		ListNode() {next=NULL;}
		ListNode(int res,int sal,int rown,int startings,int numberofs,string mys):
		       resnumber(res), saloonno(sal), rowno(rown), startingseat(startings), 
				   numberofseats(numberofs), name(mys) {next=NULL;}
	};

class Queue {
public:
	Queue();
	bool isEmpty();
	void enqueue(int res,int sal,int rown,int startings,int numberofs,string mys);
	friend int Deletefromqueue(Queue &myList,int k,int t);
	friend void Reservefromwaitinglist(Queue &Reserved,Queue &Waitinglist);
	friend void Status(int mysaloonno,Queue &Reserves,Queue &Waitinglist);
	friend void Info(int myresnumber,Queue &Reserved,Queue &Waitinglist);
	friend void Exit(Queue &Reserved,Queue &Waitinglist);
	void makeEmpty();
	void dequeue();
private:
	ListNode *front;
	ListNode *back;
};


vector<Row> mycinema;
int numberofsaloons,numberofrows;
vector<bool> reservationnumbers;
int reserves,waitings,stopflag;

Queue::Queue()
{
	front=back=NULL;
}

void Queue::dequeue()
{
	ListNode *old=front;
	front=front->next;
	if(!front)
		back=NULL;
	delete old;
}

bool Queue::isEmpty()
{
	return front==NULL;
}

void Queue::makeEmpty()
{
	while(!isEmpty())
		dequeue();
}

void Queue::enqueue(int res,int sal,int rown,int startings,int numberofs,string mys)
{
	ListNode newlistnode;
	ListNode *temp,*temp2;
	if(isEmpty())
		back=front=new ListNode(res,sal,rown,startings,numberofs,mys);
	else 
	{
		newlistnode.next=front;
		temp=&newlistnode;
		while(temp!=back && temp->next->resnumber<res)
			temp=temp->next;
		if(temp->next==front)
		{
			temp->next=new ListNode(res,sal,rown,startings,numberofs,mys);
			temp->next->next=front;
			front=temp->next;
		}
		else 
			if(temp==back)
				back=back->next=new ListNode(res,sal,rown,startings,numberofs,mys);
			else
			{
				temp2=temp->next;
				temp->next=new ListNode(res,sal,rown,startings,numberofs,mys);
				temp->next->next=temp2;
			}
	}
}

void Readcinemaconfig(char *filename)
{
	int x,y,z;
	int i;
	ifstream myinput(filename);
	if(!myinput)
	{
		cout<<"Dosya acilamadi"<<endl;
		exit(1);
	}

	myinput>>numberofsaloons;
	while(!myinput.eof())
	{
		myinput>>x>>y>>z;
		mycinema.resize(++numberofrows);
		mycinema[numberofrows-1].saloonnum=x;
		mycinema[numberofrows-1].rownum=y;
		mycinema[numberofrows-1].numberofseats=z;
		mycinema[numberofrows-1].seats.resize(z+1);
		for(i=1;i<=z;i++)
			mycinema[numberofrows-1].seats[i]=0;
	}
	myinput.close();
}

int Getinsttype(string st)
{
	if(st=="ORDER") return 1;
	if(st=="CANCEL") return 2;
	if(st=="STATUS") return 3;
	if(st=="INFO") return 4;
	if(st=="RESET") return 5;
	if(st=="EXIT") return 6;
	return 0;
}

int Getnumber(string st)
{
	int sonuc=0;
	for(int i=0;i<st.length();i++)
	{
		sonuc*=10;
		sonuc+=st[i]-'0';
	}
	return sonuc;
}

void Delreservationnumber(int k)
{
	reservationnumbers[k]=false;
}

int Getreservationnumber(void)
{
	for(int i=0;i<reservationnumbers.size();i++)
		if(!reservationnumbers[i])
		{
			reservationnumbers[i]=true;
			return i;
		}
		
		reservationnumbers.resize(reservationnumbers.size()+1);
		reservationnumbers[reservationnumbers.size()-1]=true;
		return reservationnumbers.size()-1;
}

void Removeseats(int mysaloonno,int myrowno,int mystartings,int myconsrooms)
{
	int j;
	int myend=mystartings+myconsrooms;
	for(int i=0;i<mycinema.size();i++)
		if(mysaloonno==mycinema[i].saloonnum && myrowno==mycinema[i].rownum)
		{
			for(j=mystartings;j<myend;j++)
				mycinema[i].seats[j]=0;
			break;
		}
}

void Reserveseats(int mysaloonno,int myrowno,int mystartings,int myconsrooms)
{
	int j;
	int myend=mystartings+myconsrooms;
	for(int i=0;i<mycinema.size();i++)
		if(mysaloonno==mycinema[i].saloonnum && myrowno==mycinema[i].rownum)
		{
			for(j=mystartings;j<myend;j++)
				mycinema[i].seats[j]=1;
			break;
		}
}

void Order(int saloonno,int seatswanted,string myname,Queue &Reserved,Queue &Waitinglist)
{
	int i,j=1,flag1=0,k;
	int consrooms=0;
	int newstarting;
	int newresnumber;
	char kutu;

	for(i=0;i<numberofrows;i++)
	if(saloonno==mycinema[i].saloonnum)
	{
		consrooms=0;
		for(j=1;j<=mycinema[i].numberofseats;j++)
		{
			if(!mycinema[i].seats[j])
			{
				consrooms++;
				if(consrooms==seatswanted)
				{
					newresnumber=Getreservationnumber();
					reserves++;
					newstarting=j-seatswanted+1;
					Reserved.enqueue(newresnumber,mycinema[i].saloonnum,mycinema[i].rownum,newstarting,consrooms,myname);
					cout<<"Your reservation number is "<<newresnumber<<endl;
					cout<<"row = "<<mycinema[i].rownum<<", seats = "<<newstarting;
					Reserveseats(mycinema[i].saloonnum,mycinema[i].rownum,newstarting,seatswanted);
					for(k=newstarting+1;k<=j;k++)
						cout<<","<<k;
					cout<<" are allocated for you."<<endl;
					goto atlama;
				}
			}
			else
				consrooms=0;
		}
	}

	newresnumber=Getreservationnumber();
	cout<<"Your reservation number is "<<newresnumber<<endl;
	cout<<"Sorry not enough seat, would you like to wait cancellation of other reservations [y/n]? ";
	cin.get(kutu);
	if(kutu=='y')
	{
		waitings++;
		Waitinglist.enqueue(newresnumber,saloonno,0,0,seatswanted,myname);
	}
	else
		Delreservationnumber(newresnumber);
	cin.get(kutu);
atlama:;
}

int Deletefromqueue(Queue &myList,int k,int t)
{
	int myrowno,mysaloonno,mystartings,myconsrooms;
	ListNode newlistnode,*temp,*temp2;
	if(myList.isEmpty())
		return 0;
	
	newlistnode.next=myList.front;
	temp=&newlistnode;
	while(temp!=myList.back && myList.back)
	{
		if(temp->next->resnumber==k)
		{
			myrowno=temp->next->rowno;
			mysaloonno=temp->next->saloonno;
			myconsrooms=temp->next->numberofseats;
			mystartings=temp->next->startingseat;
			if(!t)
			Removeseats(mysaloonno,myrowno,mystartings,myconsrooms);
			if(myList.front==myList.back)
			{
				delete myList.front;
				myList.front=myList.back=NULL;
			}
			else
			{
				if(temp->next==myList.front)
					myList.front=myList.front->next;
				else
				if(temp->next==myList.back)
					myList.back=temp;

				temp2=temp->next;
				temp->next=temp->next->next;
				delete temp2;
			}
			Delreservationnumber(k);
			return 1;		
		}
		temp=temp->next;	
	}
	return 0;
}

int Orderfromwaitings(Queue &Reserved,ListNode *mynode)
{
	int i,j,flag1=0;
	int consrooms=0;
	int saloonno,seatswanted;
	int newstarting;
	int newresnumber;
	string myname;
	
	myname=mynode->name;
	saloonno=mynode->saloonno;
	seatswanted=mynode->numberofseats;
	for(i=0;i<mycinema.size();i++)
	if(saloonno==mycinema[i].saloonnum)
	{
		consrooms=0;
		for(j=1;j<=mycinema[i].numberofseats;j++)
		{
			if(!mycinema[i].seats[j])
			{
				consrooms++;
				if(consrooms==seatswanted)
				{
					newresnumber=mynode->resnumber;
					reserves++;
					waitings--;
					newstarting=j-seatswanted+1;
					Reserved.enqueue(newresnumber,mycinema[i].saloonnum,mycinema[i].rownum,newstarting,consrooms,myname);
					Reserveseats(mycinema[i].saloonnum,mycinema[i].rownum,newstarting,seatswanted);
					return 1;
				}
			}
			else
				consrooms=0;
		}
	}
	return 0;
}

void Reservefromwaitinglist(Queue &Reserved,Queue &Waitinglist)
{
	ListNode newlistnode,*temp,*temp2;
	newlistnode.next=Waitinglist.front;
	
	temp=&newlistnode;
	while(temp!=Waitinglist.back && Waitinglist.back)
	{
		if(Orderfromwaitings(Reserved,temp->next))
		{
			if(Waitinglist.front==Waitinglist.back)
			{
				delete Waitinglist.front;
				Waitinglist.front=Waitinglist.back=NULL;
			}
			else
			{
				if(temp->next==Waitinglist.front)
					Waitinglist.front=Waitinglist.front->next;
				else
				if(temp->next==Waitinglist.back)
					Waitinglist.back=temp;		

				temp2=temp->next;
				temp->next=temp->next->next;
				delete temp2;
			}
		}
		else
			temp=temp->next;
	}
}

void Cancel(int cancelnumber,Queue &Reserved,Queue &Waitinglist)
{
	if(cancelnumber<reservationnumbers.size() && reservationnumbers[cancelnumber])
	{
		if(Deletefromqueue(Reserved,cancelnumber,0))
		{
			reserves--;
			Reservefromwaitinglist(Reserved,Waitinglist);		
		}
		else 
		{
			waitings--;
			Deletefromqueue(Waitinglist,cancelnumber,1);
		}
	}
}

int Saloonnumcontrol(int k)
{
	for(int i=0;i<numberofrows;i++)
		if(mycinema[i].saloonnum==k)
			return 1;
		return 0;
}

void Status(int mysaloonno,Queue &Reserved,Queue &Waitinglist)
{
	ListNode *temp;
	int flag=0;
	temp=Reserved.front;
	if(Saloonnumcontrol(mysaloonno))
	{
	while(temp)
	{
		if(temp->saloonno==mysaloonno)
		{
			flag=1;
			cout<<temp->resnumber<<" "<<temp->name<<" row = "<<temp->rowno<<" seats = "<<temp->startingseat;
			for(int i=temp->startingseat+1;i<temp->startingseat+temp->numberofseats;i++)
				cout<<"-"<<i;
			cout<<endl;
		}
		temp=temp->next;
	}
	if(!flag)
		cout<<"<Empty>"<<endl;
	}
}

void Info(int myresnumber,Queue &Reserved,Queue &Waitinglist)
{
	ListNode *temp;
	temp=Reserved.front;
	while(temp)
	{
		if(temp->resnumber==myresnumber)
		{
			cout<<temp->name<<" "<<temp->saloonno<<" row = "<<temp->rowno<<" seats = "<<temp->startingseat;
			for(int i=temp->startingseat+1;i<temp->startingseat+temp->numberofseats;i++)
				cout<<"-"<<i;
			cout<<endl;
			goto atlama;
		}
		temp=temp->next;
	}

	temp=Waitinglist.front;
	while(temp)
	{
		if(temp->resnumber==myresnumber)
		{
			cout<<temp->name<<" saloon = "<<temp->saloonno<<", number of seats requested "
				<<temp->numberofseats<<", in Waiting List"<<endl;
			break;
		}
		temp=temp->next;
	}
atlama:;
}

void Reset(Queue &Reserved,Queue &Waitinglist)
{
	reservationnumbers.resize(0);
	reserves=waitings=0;
	for(int i=0;i<numberofrows;i++)
		for(int j=1;j<=mycinema[i].numberofseats;j++)
			mycinema[i].seats[j]=0;
	Reserved.makeEmpty();
	Waitinglist.makeEmpty();
}

void Exit(Queue &Reserved,Queue &Waitinglist)
{
	ofstream myoutput("reservations.dat");
	myoutput<<reserves<<" "<<waitings<<endl;
	ListNode *temp;
	temp=Reserved.front;
	while(temp)
	{
		myoutput<<temp->resnumber<<" "<<temp->name<<" "<<temp->saloonno<<" "<<temp->rowno
			<<" "<<temp->startingseat<<" "<<temp->numberofseats<<endl;
		temp=temp->next;
	}

	temp=Waitinglist.front;
	while(temp)
	{
		myoutput<<temp->resnumber<<" "<<temp->name<<" "<<temp->saloonno<<" "<<temp->rowno
			<<" "<<temp->startingseat<<" "<<temp->numberofseats<<endl;
		temp=temp->next;
	}
	
	myoutput.close();
	cout<<"Bye ...";
	stopflag=1;
}

void Parsest(string &st,Queue &Reserved,Queue &Waitinglist)
{
	vector<string> newstrings;
	newstrings.resize(1);
	int numberofstrings=1;
	newstrings[0]="";
	for(int i=0;i<st.length();i++)
	{
		if(st[i]==' ')
		{
			numberofstrings++;
			newstrings.resize(numberofstrings);
			newstrings[numberofstrings-1]="";
		}
			else
		newstrings[numberofstrings-1]+=st[i];
	}

	int insttype;
	insttype=Getinsttype(newstrings[0]);
	switch(insttype)
	{
	case 1: if(numberofstrings==4)
				Order(Getnumber(newstrings[2]),Getnumber(newstrings[3]),newstrings[1],Reserved,Waitinglist);
		break;
	case 2: if(numberofstrings==2)
				Cancel(Getnumber(newstrings[1]),Reserved,Waitinglist);
		break;
	case 3: if(numberofstrings==2)
				Status(Getnumber(newstrings[1]),Reserved,Waitinglist);
		break;
	case 4: if(numberofstrings==2)
				Info(Getnumber(newstrings[1]),Reserved,Waitinglist);
		break;
	case 5: if(numberofstrings==1)
				Reset(Reserved,Waitinglist);
		break;
	case 6: if(numberofstrings==1)
				Exit(Reserved,Waitinglist);
		break;
	default: break;
	}
}

void Readreservationrecords(Queue &Reserved,Queue &Waitinglist)
{
	int myres,mysaloonno,myrowno,mystartings,myconsseats;
	string myname;
	int i;
	ifstream myinput("reservations.dat");
	if(myinput)
	{
		myinput>>reserves>>waitings;
		reservationnumbers.resize(reserves+waitings);
		for(i=0;i<reserves;i++)
		{
			myinput>>myres>>myname>>mysaloonno>>myrowno>>mystartings>>myconsseats;
			reservationnumbers[myres]=true;
			Reserveseats(mysaloonno,myrowno,mystartings,myconsseats);
			Reserved.enqueue(myres,mysaloonno,myrowno,mystartings,myconsseats,myname);
		}

		for(i=0;i<waitings;i++)
		{
			myinput>>myres>>myname>>mysaloonno>>myrowno>>mystartings>>myconsseats;
			reservationnumbers[myres]=true;
			Waitinglist.enqueue(myres,mysaloonno,myrowno,mystartings,myconsseats,myname);
		}		
	}
	myinput.close();
}

int main(int argc,char *argv[])
{
	Queue Reserved,Waitinglist;
	string st;
	char ch;
	Readcinemaconfig(argv[1]);
	Readreservationrecords(Reserved,Waitinglist);
	while(!stopflag)
	{
		cout<<"ceng213_hw4>> ";
		st="";
		cin.get(ch);
		while(ch!='\n')
		{
			st+=ch;
			cin.get(ch);
		}
		Parsest(st,Reserved,Waitinglist);
	}
	return 0;
}
