#include <iostream>
#include <queue>
#include <vector>
#include <cmath>
#include <ctime>

using namespace std;

class airplane
{
	public:
		int id;
		int timeEnter;
};

class runway
{
	public:
		int timeLeft;
		bool inUse;
		bool landing;
		airplane plane;
};

int main ()
{
	int running = 1;
	while (running)
	{
		queue<airplane> takeOff;
		queue<airplane> land;
		airplane tmpAir;
		runway mainRunway;
		mainRunway.inUse = false;
		int takeOffTime;
		int landingTime;
		float takeOffRate;
		float landingRate;
		int finishMin;
		int numPlanes = 0;
		int currentMin = 0;
		int totLandQueue = 0;
		int totTakeQueue = 0;
		int totLanded = 0;
		int totTakeOff = 0;
		int totLandLen = 0;
		int totTakeLen = 0;
		int numLandSize = 0;
		int numTakeSize = 0;
		int totRunwayTime = 0;
		int timeWaitLand = 0;
		int timeWaitTake = 0;

		#ifdef WIN32
			system("cls");
		#else
			system("clear");
		#endif

		cout << "Enter service time for landing queue: ";
		cin >> landingTime;
		cout << "Enter service time for takeoff queue: ";
		cin >> takeOffTime;
		cout << "Enter hourly arrival rate for landing queue ( >0 & <61 ): ";
		cin >> landingRate;
		while (landingRate < 1 || landingRate > 60)
		{
			cout << "Between 1 and 60 please: ";
			cin >> landingRate;
		}
		cout << "Enter hourly arrival rate for takeoff queue ( >0 & <61 ): ";
		cin >> takeOffRate;
		while (takeOffRate < 1 || takeOffRate > 60)
		{
			cout << "Between 1 and 60 please: ";
			cin >> takeOffRate;
		}
		cout << "Enter the number of minutes to run: ";
		cin	>> finishMin;

		srand(static_cast<unsigned>(time(0)));

		while (currentMin < finishMin)
		{
			// Update queue counters
			if (land.size() != 0)
			{
				totLandLen += (int)land.size();
				numLandSize++;
			}
			if (takeOff.size() != 0)
			{
				totTakeLen += (int)takeOff.size();
				numTakeSize++;
			}
			for (int i = 0; i < (int)land.size(); i++)
			{
				timeWaitLand++;
				airplane tmp = land.front();
				land.pop();
				land.push(tmp);
			}
			for (int i = 0; i < (int)takeOff.size(); i++)
			{
				timeWaitTake++;
				airplane tmp = takeOff.front();
				takeOff.pop();
				takeOff.push(tmp);
			}

			cout << "Time : " << currentMin << endl;

			// If rand is less then landingRate / 60 put a plane in the land queue
			if (rand() / (RAND_MAX + 1.0) < (landingRate / 60))
			{
				// Generate a random flight and put it on queue
				tmpAir.id = rand();
				tmpAir.timeEnter = currentMin;
				cout << "  Flight #" << tmpAir.id << " is now waiting to land" << endl;
				land.push(tmpAir);
				totLandQueue++;
			}

			// If rand is less then takeOffRate / 60 put a plane in the land queue
			if (rand() / (RAND_MAX + 1.0) < (takeOffRate / 60))
			{
				// Generate a random flight number and put it on queue
				tmpAir.id = rand();
				tmpAir.timeEnter = currentMin;
				cout << "  Flight #" << tmpAir.id << " is now waiting to take off" << endl;
				takeOff.push(tmpAir);
				totTakeQueue++;
			}

			if (!mainRunway.inUse)
			{
				if (land.size() != 0)
				{
					// Put plane on runway from queue then pop it off the queue
                    mainRunway.plane = land.front();
					mainRunway.inUse = true;
					mainRunway.landing = true;
					// Pop the plane off the landing queue
					land.pop();
					// Set information about plane on runway
					mainRunway.timeLeft = landingTime;
					cout << "  Flight #" << mainRunway.plane.id 
						<< " is now landing" << endl;
				}
				else if(takeOff.size() > 0)
				{
					// Put plane on runway from queue then pop it off the queue
					mainRunway.plane = takeOff.front();
					mainRunway.inUse = true;
					mainRunway.landing = false;
					takeOff.pop();
					// Set information about plane on runway
					mainRunway.timeLeft = takeOffTime;
					cout << "  Flight #" << mainRunway.plane.id 
						<< " is now taking off" << endl;
				}
			}
			if (mainRunway.inUse)
			{
				if (mainRunway.timeLeft == 0)
				{
					if (mainRunway.landing)
						totLanded++;
					else
						totTakeOff++;
					cout << "  Flight #" << mainRunway.plane.id
						<< " is off the runway" << endl;
					mainRunway.inUse = false;
				}
				else
				{
					totRunwayTime++;
					mainRunway.timeLeft--;
				}
			}
			currentMin++;
		}

		cout << "--------------------------------------------" << endl;
		cout << "Simulation ended at minute " << currentMin << "!" << endl;
		cout << "--------------------------------------------" << endl;
		cout << "|                 Totals                   |" << endl;
		cout << "--------------------------------------------" << endl;
		cout << "Time of planes on runway: " << totRunwayTime << " mins" << endl;
		cout << "Planes that landed: " << totLanded << endl;
		cout << "Planes that took off: " << totTakeOff << endl;
		cout << "Planes queued for landing: " << totLandQueue << endl;
		cout << "Planes queued for take off: " << totTakeQueue << endl;
		cout << "Time planes spent in landing queue: " << timeWaitLand << endl;
		cout << "Time planes spent in take off queue: " << timeWaitTake << endl;
		cout << "Avg time spent in landing queue: " << (float)timeWaitLand / (float)totLandQueue << endl;
		cout << "Avg time spent in take off queue: " << (float)timeWaitTake / (float)totTakeQueue << endl;
		cout << "Avg landing queue length: " << (float)totLandLen / (float)numLandSize  << " " << totLandLen << " / " << numLandSize << endl;
		cout << "Avg take off queue length: " << (float)totTakeLen / (float)numTakeSize << " " << totTakeLen << " / " << numTakeSize << endl;
		cout << "--------------------------------------------" << endl;
		cout << endl << "Press 1 to run again or 0 to exit: ";
		cin >> running;
	}
	system("pause");
	return 0;
}
