#include<iostream>
#include<queue>

using namespace std;

class process{
	public:
	int process_id;
  	int priority;
  	int burst_time;
  	int queue_no;
  	int waiting_time=0;
  	int remaining_time=0;
  	int start_time=-1;
  	int end_time=-1;
  	
  	
  	void getdata()
		{
  			cout<<"\nEnter the process ID: ";
  			cin>>this->process_id;
  			cout<<"\nEnter the priority: \n";
  			cin>>this->priority;
  			cout<<"\nEnter the Burst time: ";
  			cin>>this->burst_time;
  			this->remaining_time = this->burst_time;
    		if(this->priority <7 && this->priority >3){
      			this->queue_no = 2;
    		}
    		else if (this->priority <=3 && this->priority >0 )
    		{
      			this->queue_no = 3;
    		}
    		else if (this->priority >=7)
    		{
      			this->queue_no = 1;  
    		}
    		else{
      			cout<<"Invalid priority:\n";
      		exit(1);
    		}
		}
	void display(){
		cout<<"\n"<<this->process_id<<" | "<<this->burst_time<<" | "<<this->start_time<<" | "<<this->end_time;
	}

};
int global_time, exec_remain, local_time=10;


void RoundRobin(queue <process> *q1){
	
	int quantum =4;
	int n =q1->size();
	process p2[n];
	int i=0;
	while(q1->empty()==0){
		p2[i]=q1->front();
		q1->pop();
		i++;
	}
	
  cout<<global_time<<"\tRb\n"<<endl;
       
        for( i=0;i<n;i++)
		{	
			if(quantum<=local_time )
			{
				if(p2[i].start_time==-1)
					{
						p2[i].start_time=global_time;					
					}
				if(p2[i].remaining_time>=quantum)
					{
						p2[i].remaining_time=p2[i].remaining_time-quantum;
						global_time=global_time+quantum;
						local_time-=quantum;
					}
				if(p2[i].remaining_time<quantum && p2[i].remaining_time>0)
					{	
					global_time=global_time + p2[i].remaining_time;
					local_time-=p2[i].remaining_time;
					p2[i].remaining_time=0;
					}
				if(p2[i].remaining_time==0 && p2[i].end_time==-1)
				{
					p2[i].end_time=global_time;
					exec_remain--;		
				}
			}q1->push(p2[i]);
		}
		local_time=10;
} 
  
void PriorityQ(queue <process> *q2){
	int n =q2->size();
	process p2[n];
	int i=0;
	while(q2->empty()==0){
		p2[i]=q2->front();
		q2->pop();
		i++;
		}	
    cout<<global_time<<"\tPriority\n";
   process temp;
   for (int i = 0; i < n-1; i++)       
  		{   
       		for (int j = 0; j < n-i-1; j++)  
           		if (p2[j+1].priority > p2[j].priority) 
              		{
              				temp = p2[j+1];
              				p2[j+1]=p2[j];
              				p2[j]=temp;
					} 
		}
	for(i=0;i<n;i++)
		{	
			if(p2[i].remaining_time <= local_time &&  p2[i].remaining_time > 0)
			{
		
				if(p2[i].start_time == -1)
					{
						p2[i].start_time = global_time;
					}
				
				global_time=global_time+p2[i].remaining_time;
				local_time-=p2[i].remaining_time;
				p2[i].remaining_time = 0;
				if(p2[i].remaining_time==0&& p2[i].end_time==-1)
				{
					p2[i].end_time=global_time;
					exec_remain--;
				}
			}
			else
			{
				if((p2[i].remaining_time-local_time>0)&&p2[i].remaining_time>0)
				{
					if(p2[i].start_time==-1)
					{
						p2[i].start_time=global_time;
					}
					p2[i].remaining_time=p2[i].remaining_time-local_time;
					global_time=global_time+local_time;
					local_time=0;
					if(p2[i].remaining_time == 0 && p2[i].end_time==-1)
					{
						p2[i].end_time = global_time;
						exec_remain--;
						
					}
				}
			}
			q2->push(p2[i]);
		}
		local_time=10;
}

void FCFS(queue <process> *q3){
	int n =q3->size();
	process p2[n];
	int i=0;
	while(q3->empty()==0){
		p2[i]=q3->front();
		q3->pop();
		i++;
		}	
    cout<<global_time<<"\tFCFS\n";
	for(i=0;i<n;i++)
		{	
			if(p2[i].remaining_time <= local_time &&  p2[i].remaining_time > 0)
			{
				
				if(p2[i].start_time == -1)
					{
						p2[i].start_time = global_time;
					}
				
				global_time=global_time+p2[i].remaining_time;
				local_time-=p2[i].remaining_time;
				p2[i].remaining_time = 0;
				if(p2[i].remaining_time==0&& p2[i].end_time==-1)
				{
					p2[i].end_time=global_time;
					exec_remain--;
				}
			}
			else
			{
				if((p2[i].remaining_time>local_time)&&(p2[i].remaining_time>0))
				{
					if(p2[i].start_time==-1)
					{
						p2[i].start_time=global_time;
					}
					p2[i].remaining_time=p2[i].remaining_time-local_time;
					global_time=global_time+local_time;
					local_time=0;
					if(p2[i].remaining_time == 0 && p2[i].end_time==-1)
					{
						p2[i].end_time = global_time;
						exec_remain--;
					}
				}
			}
			q3->push(p2[i]);
		}
		local_time=10;
}

int main(){
	cout<<"Enter the number of processes [Maximum 20 processes]: ";
	int n;
	cin>>n;
	process p[20];
	for(int i=0;i<n ; i++){
		p[i].getdata();
	}
	queue <process> queue1,queue2, queue3;
	for(int i=0;i<n;i++){
		if(p[i].queue_no==1){
			queue1.push(p[i]);
		}
		else if(p[i].queue_no==2){
			queue2.push(p[i]);
		}
		else{
			queue3.push(p[i]);
		}
	}
	
cout<<"Global time\tQueue"<<endl;
	exec_remain = n;
	while(exec_remain >0){
		RoundRobin(&queue1);
		PriorityQ(&queue2);
		FCFS(&queue3);

		
	}
	cout<<"\nId | Burst Time | Start Time | Turnaround Time";
	int n1 = queue1.size();
	int n2 = queue2.size();
	int n3 = queue3.size();
	process p1[n1], p2[n2], p3[n3];
	int i=0;
	while(queue1.empty()==0){
		p1[i]=queue1.front();
		queue1.pop();
		i++;
		}	
	while(queue2.empty()==0){
		p2[i]=queue2.front();
		queue2.pop();
		i++;
	}	
	while(queue3.empty()==0){
		p3[i]=queue3.front();
		queue3.pop();
		i++;
	}	
	
	for(int i=0;i<n1;i++)
	{
		p1[i].display();
	}
	
		for(int i=0;i<n2;i++)
	{
		p2[i].display();
	}
	
		for(int i=0;i<n3;i++)
	{
		p3[i].display();
	}
}
