// multi.cpp     Dave Reed      9/9/03
//
// SIMPLE multiprogramming simulator.  A collection of jobs are read in from
// a file, and then executed using timesharing (TIME_SLICE set as a constant).
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <iomanip>
#include <string>
#include "Job.h"
#include "Queue.h"
#include "JobStream.h"
using namespace std;

const int TIME_SLICE = 1000;            // time slice duration for time sharing
const int LOAD_DELAY = 5;               // setup time for a new job
const string JOB_FILE = "jobs.dat";     // file containing job data

int main()
{
  JobStream ArrivingJobs(JOB_FILE); 
  Queue<Job> ReadyQueue;
  int time = 1, slice_count = TIME_SLICE;
  bool loadJob = true;

  while (!ReadyQueue.IsEmpty() || ArrivingJobs.JobsRemaining()) {
    while (ArrivingJobs.JobHasArrived(time)) {
      Job newJob = ArrivingJobs.GetJob();
      ReadyQueue.Enter(newJob);
      cout << setw(4) << time << ": JOB " << newJob.GetID() 
           << " ARRIVES (length = " << newJob.GetLength() << ")" << endl;
    }

    if (!ReadyQueue.IsEmpty()) {
      Job & currentJob = ReadyQueue.Front();

      if (slice_count == TIME_SLICE) {
        if (loadJob) {
          cout << setw(4) << time << ":   LOAD JOB " << currentJob.GetID() << endl;
          time += LOAD_DELAY;
          loadJob = false;
        }
        cout << setw(4) << time << ":     START JOB " << currentJob.GetID() << endl;
      }

      time++;
      slice_count--;
      JobStatus status = currentJob.Execute();;
        
      if (status == DONE) {
        cout << setw(4) << time << ":       FINISH JOB " << currentJob.GetID() << endl;
        ReadyQueue.Remove();

        slice_count = TIME_SLICE;
        loadJob = true;
      }
      else if (slice_count == 0) {
        cout << setw(4) << time << ":       TIMEOUT JOB " << currentJob.GetID() << endl;
        Job saveJob = currentJob;
        ReadyQueue.Remove();
            
        slice_count = TIME_SLICE;
        loadJob = (!ReadyQueue.IsEmpty());

        ReadyQueue.Enter(saveJob);
      }
    }
  }
  cout << "DONE PROCESSING" << endl;
  return 0;
}

