// ========================================================================================
// You will complete the Simulator class.
// You may edit this file as needed.
// ========================================================================================

#include <iostream>
#include <iomanip>
#include <cassert>
#include <algorithm>

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


Simulator::Simulator(const TimeStamp &t, int n, const std::string &a,
                     const std::string &vf, const std::string &lf) :
  current(t), num_processors(n), algorithm(a), vis_str(vf), log_str(lf) {

  // initialize the member variables
  processors = std::vector<Job>(num_processors);
  job_count = 0;
  total_waiting_time = 0;
  max_waiting_time = 0;
  non_idle_time = 0;

  // verify that the output filestreams were opened successfully
  // (if the filenames are not empty string)
  if (vf != "") {
    assert (vis_str.good());
    // print a header row for the ASCII art visualization table
    vis_str << "timestamp";
    for (int i = 0; i < num_processors; i++) {
      vis_str << "| processor " << std::left << std::setw(11) << i;
    }
    vis_str << "| queue" << std::endl;
  }
  if (lf != "") {
    assert (log_str.good());
  }
}
 

bool Simulator::done() const {

  // placeholder code
  return true;

}


void Simulator::assignJobs() {
  if (algorithm == "single_file") {

    // placeholder code

  } else if (algorithm == "first_available") {

    // placeholder code

  } else if (algorithm == "keep_busy") {

    // placeholder code

  } else if (algorithm == "custom") {

    // placeholder code

  } else {
    std::cerr << "ERROR: Unknown Algorithm '" << algorithm << "'" << std::endl;
    exit(1);
  }
}


void Simulator::printVisualizationRow() {
  if (vis_str.good()) {
    vis_str << current;
    for (int i = 0; i < num_processors; i++) {
      vis_str << " | " << std::setfill(' ') << std::setw(20) << std::left
              << processors[i].getName();
    }
    vis_str << " | " << std::right << std::setw(5) << todo.size() << std::endl; 
  }
}


void Simulator::printLogRow() {
  std::string name = "placeholdername";
  TimeStamp uploadtime;
  TimeStamp starttime;
  TimeStamp finishtime;
  int waitingtime = 0;
  int gradingtime = 0;
  if (log_str.good()) {
    log_str << std::left << std::setw(20) << name << "  "
            << "upload: " << uploadtime << "  "
            << "started grading: " << starttime << "  "
            << "finished grading: " << finishtime << "  "
            << "wait_time: " << std::right << std::setfill(' ') << std::setw(4) << waitingtime << " sec  "
            << "grading_time: " << std::setw(4) << gradingtime << " sec" << std::endl;
  }
}


void Simulator::printSummaryStatistics(float simulation_running_time) {
  int elapsed_seconds = elapsed(TimeStamp(23,0,0),current);
  float average_waiting = total_waiting_time / float(job_count);
  int processor_time = num_processors * elapsed_seconds;
  double idle_percent  = 100 * (processor_time - non_idle_time) / double(processor_time);
  std::cout << "number of jobs:          " << std::right << std::setw(15) << job_count << std::endl;
  std::cout << "scheduling algorithm:    " << std::right << std::setw(15) << algorithm << std::endl;
#ifdef VECTOR
  std::cout << "data structure:              std::vector" << std::endl;
#else
  std::cout << "data structure:                std::list" << std::endl;
#endif
  std::cout << "time to empty queue:     "
            << std::setw(8) <<  elapsed_seconds << "    sec" << std::endl;
  std::cout << "average waiting time:    "
            << std::fixed << std::setprecision(2) << std::setw(11) << average_waiting << " sec" << std::endl;
  std::cout << "maximum waiting time:    "
            << std::setw(8) << max_waiting_time << "    sec" << std::endl;
  std::cout << "idle percentage:         "
            << std::right << std::setw(11) << std::fixed << std::setprecision(2) << idle_percent << "   %" << std::endl;
  std::cout << "simulation running time: "
	    << std::setw(11) << std::fixed << std::setprecision(2) << simulation_running_time << " sec" << std::endl;
}
