// CS1704 - Summer 2000
// Project One
// Hussein Suleman
// July 2000

#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cstdlib>

using namespace std;

// maximum number of flights to display
#define maxflights 5

// type definition for date and time storage 
typedef struct {
	unsigned int Minute;
	unsigned int Hour;
	unsigned int Day;
	unsigned int Month;
	unsigned int Year;
} DateTimeType;

// type definition for basic unit of data to be stored wrt each flight
typedef struct {
	char Airline[11];
	char Flight[7];
	char From[21];
	DateTimeType DateTime;
	char Status[16];
} FlightType;

// convert regular time and date structure to a single number of minutes 
// in a manner similar to Julian dates
unsigned long int JulietTime ( const DateTimeType & DateTime ) 
{
	return DateTime.Minute + 
		    (DateTime.Hour*60) + 
			 (DateTime.Day*24*60) + 
			 (DateTime.Month*31*24*60) +
			 ((DateTime.Year-1900)*12*31*24*60);
}

// list up to a maximum of maxflights flights on the screen
void ListFlights ( FlightType FlightList [], unsigned int NumberOfFlights )
{
	cout << "\nFlight Arrivals\n\n"
		  << "Airline    Flight From                 Time  Date  Status\n"
		  << "-------    ------ ----                 ----  ----  ------\n";
	unsigned int i=0;
	while ((i<maxflights) && (i<NumberOfFlights))
	{
		cout << setw(10) << setiosflags(ios::left) << FlightList[i].Airline << " "
		     << setw(6) << FlightList[i].Flight << " "
			  << setw(20) << FlightList[i].From << " "
		     << setw(2) << setfill('0') << resetiosflags(ios::left) 
			  << FlightList[i].DateTime.Hour << ":"
			  << setw(2) << FlightList[i].DateTime.Minute << " "
			  << setw(2) << FlightList[i].DateTime.Month << "/"
			  << setw(2) << FlightList[i].DateTime.Day << " "
			  << setw(15) << setiosflags(ios::left) << setfill(' ') 
			  << FlightList[i].Status << "\n";
		i++;
	}
}

// add a flight to the array by using an insertion sort procedure
int AddFlight ( string & Airline, string & Flight, string & From, string & Minute, 
					 string & Hour, string & Day, string & Month, string & Year,
					 string & Status, FlightType FlightList [], unsigned int & NumberOfFlights )
{
	DateTimeType DateTime;

	// convert date/time to integers and do error checking
	if (NumberOfFlights == 100)
		return 1;
	DateTime.Hour = atoi (Hour.c_str ());
	if ((DateTime.Hour < 0) || (DateTime.Hour > 23))
		return 1;
	DateTime.Minute = atoi (Minute.c_str ());
	if ((DateTime.Minute < 0) || (DateTime.Minute > 59))
		return 1;
	DateTime.Day = atoi (Day.c_str ());
	if ((DateTime.Day < 1) || (DateTime.Day > 31))
		return 1;
	DateTime.Month = atoi (Month.c_str ());
	if ((DateTime.Month < 1) || (DateTime.Month > 12))
		return 1;
	DateTime.Year = atoi (Year.c_str ());
	if (DateTime.Year < 1900)
		return 1;
	if ((Airline == "") || (Flight == "") || (From == "") || (Status == ""))
		return 1;

	// find and make space for new entry
	unsigned int Position = NumberOfFlights;
	unsigned long int NewTime = JulietTime (DateTime);
	while ((Position > 0) && (JulietTime (FlightList[Position-1].DateTime) >= NewTime))
	{
		FlightList[Position] = FlightList[Position-1];
		Position--;
	}

	// copy new values and increment counter
	strcpy (FlightList[Position].Airline, Airline.substr (0, 10).c_str ());
	strcpy (FlightList[Position].Flight, Flight.substr(0, 6).c_str ());
	strcpy (FlightList[Position].From, From.substr (0, 20).c_str ());
	FlightList[Position].DateTime = DateTime;
	strcpy (FlightList[Position].Status, Status.substr (0, 15).c_str ());
	NumberOfFlights++;

	return 0;
}

// search for and delay a flight
int DelayFlight ( string & Airline, string & Flight,
						FlightType FlightList [], unsigned int NumberOfFlights )
{
	// find flight by sequential search
	unsigned int i=0;
	while ((i<NumberOfFlights) && ((FlightList[i].Airline != Airline) || 
		                            (FlightList[i].Flight != Flight)))
		i++;

	// delay flight
	if (i<NumberOfFlights)
	{
		strcpy (FlightList[i].Status, "Delayed");
		return 0;
	}
	else
		return 1;
}

// search for and remove a flight
int RemoveFlight ( string & Airline, string & Flight,
						 FlightType FlightList [], unsigned int & NumberOfFlights )
{
	// find flight by sequential search
	unsigned int i=0;
	while ((i<NumberOfFlights) && ((FlightList[i].Airline != Airline) || 
		                            (FlightList[i].Flight != Flight)))
		i++;

	// remove flight
	if (i<NumberOfFlights)
	{
		while (i<(NumberOfFlights-1))
		{
			FlightList[i] = FlightList[i+1];
			i++;
		}
		NumberOfFlights--;
		return 0;
	}
	else
		return 1;
}

// load a batch file from disk and process it
void LoadFromDisk ( string & Filename, FlightType FlightList [], unsigned int & NumberOfFlights )
{
	string Operation, Airline, Flight, From, Status, junk;
	string Minute, Hour, Day, Month, Year;

	ifstream f (Filename.c_str (), ios::in);

	if (!f) 
		return;

	while (!f.eof ())
	{
		f >> Operation;
		if (!f.eof ())
		{
			if (Operation == "add")
			{
				f >> Airline >> Flight >> From >> 
					  Minute >> Hour >> Day >> Month >> Year;
				Status = "OnTime";
				if (AddFlight (Airline, Flight, From, Minute, Hour, Day, Month, Year, 
									Status, FlightList, NumberOfFlights))
					cout << "add: Error in flight information [" << Airline << ", " << Flight << "]\n";
			}
			else if (Operation == "delay")
			{
				f >> Airline >> Flight;
				if (DelayFlight (Airline, Flight, FlightList, NumberOfFlights))
					cout << "delay: Flight not found [" << Airline << ", " << Flight << "]\n";
			}
			else if (Operation, "remove")
			{
				f >> Airline >> Flight;
				if (RemoveFlight (Airline, Flight, FlightList, NumberOfFlights))
					cout << "remove: Flight not found [" << Airline << ", " << Flight << "]\n";
			}
			getline (f, junk);
		}
	}
}

// initialize the array
void Initialize ( unsigned int & NumberOfFlights )
{
	NumberOfFlights = 0;
}

// interact with the user to enter a new flight
void AddFlightOption ( FlightType FlightList [], unsigned int & NumberOfFlights )
{
	string Airline, Flight, From, Status;
	string Minute, Hour, Day, Month, Year;

	cout << "Enter the Airline Name : ";
	cin >> Airline;
	cout << "Enter the Flight Number : ";
	cin >> Flight;
	cout << "Enter the Location From where the flight is arriving : ";
	cin >> From;
	cout << "Enter the Time/Date in \"minute hour day month year\" format : ";
	cin >> Minute >> Hour >> Day >> Month >> Year;
	Status = "OnTime";

	if (AddFlight (Airline, Flight, From, Minute, Hour, Day, Month, Year, 
						Status, FlightList, NumberOfFlights))
		cout << "add - Error in flight information [" << Airline << ", " << Flight << "]\n";
}

// interact with the user to remove a flight
void RemoveFlightOption ( FlightType FlightList [], unsigned int & NumberOfFlights )
{
	string Airline;
	string Flight;

	cout << "Enter the Airline Name : ";
	cin >> Airline;
	cout << "Enter the Flight Number : ";
	cin >> Flight;

	if (RemoveFlight (Airline, Flight, FlightList, NumberOfFlights))
		cout << "remove - Flight not found [" << Airline << ", " << Flight << "]\n";
}

// interact with the user to delay a flight
void DelayFlightOption ( FlightType FlightList [], unsigned int NumberOfFlights )
{
	string Airline;
	string Flight;

	cout << "Enter the Airline Name : ";
	cin >> Airline;
	cout << "Enter the Flight Number : ";
	cin >> Flight;

	if (DelayFlight (Airline, Flight, FlightList, NumberOfFlights))
		cout << "delay - Flight not found [" << Airline << ", " << Flight << "]\n";
}

// interact with the user to process a batch job
void LoadFromDiskOption ( FlightType FlightList [], unsigned int & NumberOfFlights )
{
	string Filename;

	cout << "Enter the filename : ";
	cin >> Filename;

	LoadFromDisk (Filename, FlightList, NumberOfFlights);
}

//
// main program body
//

void main ()
{
	FlightType FlightList[100];
	unsigned int NumberOfFlights;

	Initialize (NumberOfFlights);
	
	char ch;
	do {
		ListFlights (FlightList, NumberOfFlights);
		cout << "\nOptions: [A]dd Flight / [R]emove / [D]elay / [L]oad from disk / [Q]uit\n\n"
			  << "Enter an option and press ENTER : ";
		cin >> ch;
		ch = tolower (ch);
		switch (ch)
		{
		   case 'a' : AddFlightOption (FlightList, NumberOfFlights); break;
			case 'r' : RemoveFlightOption (FlightList, NumberOfFlights); break;
			case 'd' : DelayFlightOption (FlightList, NumberOfFlights); break;
			case 'l' : LoadFromDiskOption (FlightList, NumberOfFlights); break;
		}
	} while (ch!='q');
}
