// ========================================================================================
// IMPORTANT: You should not edit this file
// ========================================================================================

#include <iostream>
#include <fstream>
#include <cassert>
#include <string>
#include <ctime>
#include <sys/time.h>
#include <sys/resource.h>

#include "timestamp.h"
#include "job.h"
#include "simulator.h"

int main(int argc, char* argv[]) {

  // ========================================================================================
  // PARSE THE COMMAND LINE ARGUMENTS
  assert (argc >= 3);
  std::ifstream istr(argv[1]);
  int num_processors = std::stoi(argv[2]);
  assert (istr.good());
  assert (num_processors >= 1);
  
  std::string scheduler_algorithm = "single_file";
  std::string visualization_file = "";
  std::string log_file = "";

  for (int i = 3; i < argc; i++) {
    if (std::string(argv[i]) == "--algorithm") {
      i++;
      assert (i < argc);
      scheduler_algorithm = argv[i];
    } else if (std::string(argv[i]) == "--visualization") {
      i++;
      assert (i < argc);
      visualization_file = argv[i];
    } else if (std::string(argv[i]) == "--log") {
      i++;
      assert (i < argc);
      log_file = argv[i];
    } else {
      std::cerr << "UNKNOWN COMMAND LINE ARGUMENT: " << argv[i];
      exit(1);
    }
  }

  // we will always start the simulation at 11pm
  TimeStamp simulation_start_time(23,0,0);

  // create the simulation object
  Simulator simulator(simulation_start_time, num_processors, scheduler_algorithm, visualization_file, log_file);

  // ========================================================================================
  // RUN THE SIMULATION

  // Mark the real time before we start simulation
  clock_t time_before_simulation = clock();

  // parsing variables
  int hours, minutes, seconds;
  char tmp1, tmp2;
  
  while (istr >> hours >> tmp1 >> minutes >> tmp2 >> seconds) {

    // Read the upload timestamp for the next job in the input file.
    assert (tmp1 == ':');
    assert (tmp2 == ':');
    assert (hours == 23);
    assert (minutes >= 0 && minutes < 60);
    assert (seconds >= 0 && seconds < 60);
    TimeStamp upload_time(hours, minutes, seconds);

    // Advance the simulation foward (if needed) so that the
    // simulation time is greater than or equal to the upload
    // timestamp of this job.
    while (simulator.getCurrentTime() < upload_time) {
      simulator.assignJobs();
      simulator.printVisualizationRow();
      simulator.tick(5);
    }

    // Read the the job data and add it to the simulation.
    std::string course, gradeable, username;
    int needed_processors, maximum_runtime, actual_runtime;    
    istr >> course >> gradeable >> username >> needed_processors >> maximum_runtime >> actual_runtime;
    assert (needed_processors >= 1);
    assert (needed_processors <= num_processors);
    assert (maximum_runtime >= 1);
    assert (actual_runtime >= 1);
    assert (maximum_runtime >= actual_runtime);
    Job job(course, gradeable, username, upload_time, needed_processors, maximum_runtime, actual_runtime);
    simulator.addJob(job);
  }

  // We have read all of the jobs from the input file, but there may
  // still be autograding jobs running and/or autograding jobs waiting
  // in the queue.  Continue to run the simulation until all jobs are
  // finished.
  while (!simulator.done()) {
    simulator.assignJobs();
    simulator.printVisualizationRow();
    simulator.tick(5);
  }

  // Mark the real time after simulation is finished.
  clock_t time_after_simulation = clock();
  float simulation_running_time = float(time_after_simulation-time_before_simulation) / float(CLOCKS_PER_SEC);

  // ========================================================================================  
  // Print the summary statistics to std::cout
  simulator.printSummaryStatistics(simulation_running_time);
}
