/* main.cpp
 *
 * The main code for the elevator simulation.
 */


#include <iostream.h>
#include <stdlib.h>
#include "floor.H"
#include "elevator.H"
#include "stats.H"
#include "sched.H"
#include "control.H"
#include "graphics.H"
#include "opengl.H"
#include "main.H"
#include "events.H"


Controller *controller;		// elevator controller
Scheduler  scheduler;		// event scheduler
Statistics statistics;		// statistics gatherer
Graphics   graphics;		// graphics output
OpenGL     gl;			// OpenGL interface

Floor floors[MAX_FLOORS];	// the floors
Elevator elevators[MAX_ELEVS];	// the elevators

int num_floors = 5;		// number of floors
int num_elevators = 3;		// number of elevators
int elev_capacity = 12;		// capacity of each elevator
float elev_accel = 0.2;		// rate of acceleration in floors/sec/sec
float elev_delay = 1.0;		// elevator delay to unload/load passengers
float mean_arrival_time = 3.7;	// mean time between arrival on a floor
long int seed = 1398413298;	// random seed
float current_time = 0;		// simulation time
float stop_time = 100;		// stopping time
ColourMode colour_mode = COLOUR;// MONO, GREY, or COLOUR

int draw_graphics = 1;		// 1 -> graphical output
int redraw_upon_event = 0;	// 1 -> redraw upon ElevatorArrival or
				//  PersonAppearance
int redraw_regularly = 1;	// 1 -> redraw at fixed intervals
float report_interval = 0.5;	// interval for regular redrawing
int text_output = 0;		// 1 -> output textual reports of events

/* mean_wait_time is a simulation parameter for the impatient person class */
float mean_wait_time = 20.0;



void parse_command_line( int argc, char **argv );


/* Create all the pieces, then handle all the events, then
 * report the statistics.
 */

int
main( int argc, char **argv )
{
    ReportEvent *event;
    int i;

    cout.precision(4);
    parse_command_line( argc, argv );

    if (num_floors > MAX_FLOORS) {
	cerr << "Too many floors (maximum is " << MAX_FLOORS << ")\n";
	exit(1);
    }

    if (num_elevators > MAX_ELEVS) {
	cerr << "Too many elevators (maximum is " << MAX_ELEVS << ")\n";
	exit(1);
    }

    /*THIS MUST BE CHANGED FOR WINDOWS*/
    srand(seed);

    /* Set up the window */

    graphics.init( num_elevators, num_floors, colour_mode );

    /* Create floors */

    for (i=0; i<num_floors; i++)
	floors[i].init(i);

    /* Create elevators */

    for (i=0; i<num_elevators; i++)
	elevators[i].init( elev_capacity, &floors[ (i*7) % num_floors ],
			   i, elev_accel );

    /* Create controller */

    controller = new Controller( num_floors, num_elevators );

    /* Set up the initial events */

    for (i=0; i<num_floors; i++)
	floors[i].schedule_next_appearance();

    event = new ReportEvent( current_time + report_interval );
    scheduler.add_event( event );

    /* Process all events */

    while ((current_time < stop_time || stop_time == -1) &&
	   scheduler.events_remain()) {
	scheduler.handle_next_event();
    }

    /* Report */

    if (!text_output)
	cout << "\r";

    statistics.final_report();

    return 0;
}


/* Display the list of command-line options.
 */


#define STATUS(x)  if (x) cerr << "ENABLED)\n"; else cerr << "DISABLED)\n"


void 
display_help( char *arg )

{
    cerr << "Unrecognized option " << arg << "\n";
    cerr << "Options:  -f #    number of floors (currently "
	 << num_floors << ")\n";
    cerr << "          -e #    number of elevators (currently "
	 << num_elevators << ")\n";
    cerr << "          -c #    capacity of each elevator (currently "
	 << elev_capacity << ")\n";
    cerr << "          -a #    mean time between arrivals on a floor (currently "
	 << mean_arrival_time << ")\n";
    cerr << "          -s #    stop time (currently " << stop_time << ")\n";
    cerr << "          -r #    random seed (currently "
	 << seed << ")\n";
    cerr << "          -m ?    colour mode; one of c, g, or m for colour, grey, or mono (currently ";
    switch (colour_mode) {
    case MONO: cerr << "m)\n"; break;
    case GREY: cerr << "g)\n"; break;
    case COLOUR: cerr << "c)\n"; break;
    }
    cerr << "          -dg     draw graphics (currently ";
    STATUS(draw_graphics);
    cerr << "          -dr     draw at regular intervals (currently ";
    STATUS(redraw_regularly);
    cerr << "          -de     draw at elevator arrival and person appearance (currently ";
    STATUS(redraw_upon_event);
    cerr << "          -i #    time of regular drawing interval, if enabled (currently "
	 << report_interval << ")\n";
    cerr << "          -t      text output of events (currently ";
    STATUS(text_output);
    cerr << "The options shown to be ENABLED or DISABLED are switched between modes with\n";
    cerr << "the corresponding flag.  e.g.  -dg disables graphics, since it's usually enabled\n";

    exit(1);
}


/* Set any options that appear on the command line.
 */


void
parse_command_line( int argc, char **argv )

{
    while (argc > 1) {

	argc--;
	argv++;

	if (argv[0][0] != '-')
	    display_help( argv[0] );
	else
	    switch (argv[0][1]) {
	    case 'f':
		num_floors = atoi( argv[1] );
		argv++; argc--;
		break;
	    case 'e':
		num_elevators = atoi( argv[1] );
		argv++; argc--;
		break;
	    case 'c':
		elev_capacity = atoi( argv[1] );
		argv++; argc--;
		break;
	    case 'i':
		report_interval = atof( argv[1] );
		argv++; argc--;
		break;
	    case 'a':
		mean_arrival_time = atof( argv[1] );
		argv++; argc--;
		break;
	    case 's':
		stop_time = atof( argv[1] );
		argv++; argc--;
		break;
	    case 't':
		text_output = 1 - text_output;
		break;
	    case 'r':
		seed = atoi( argv[1] );
		argv++; argc--;
		break;
	    case 'd':
		if (argv[0][2] == 'r')
		    redraw_regularly = 1 - redraw_regularly;
		else if (argv[0][2] == 'e')
		    redraw_upon_event = 1 - redraw_upon_event;
		else if (argv[0][2] == 'g')
		    draw_graphics = 1 - draw_graphics;
		else
		    display_help( argv[0] );
		break;
	    case 'm':
		if (argc <= 1) {
		    cerr << "Flag -m requires additional argument\n";
		    exit(1);
		}
		switch (argv[1][0]) {
		case 'm': colour_mode = MONO; break;
		case 'g': colour_mode = GREY; break;
		case 'c': colour_mode = COLOUR; break;
		default:
		    cerr << "Colour mode must be one of c, g, or m, not "
			 << argv[1] << "\n";
		    exit(1);
		}
		argv++; argc--;
		break;

	    default:
		display_help( argv[0] );
	    }
    }
}
