
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <queue>
#include "Job.h"
#include "CPUScheduler.h"
using namespace std;

CPUScheduler::CPUScheduler(string filename, int delay, int slice)
// Assumes: filename contains job data, delay >= 0, slice > 0
// Results: constructs a CPUScheduler with specified load delay and time slice
{
    timeSlice = slice;
    loadDelay = delay;

    sliceTimeRemaining = timeSlice;
    loadTimeRemaining = loadDelay;

    currentTime = 0;

    ifstream jobFile(filename.c_str());
    if (!jobFile) {
        cout << "File not found." << endl;
        exit(1);
    }

    Job nextJob;
    while (nextJob.read(jobFile)) {
        readyQueue.push(nextJob);
    }
    jobFile.close();
}

bool CPUScheduler::jobsRemaining() const
// Returns: true if any jobs remaining in the readyQueue
{
    return (readyQueue.size() > 0);
}

void CPUScheduler::execute()
// Results: performs one CPU cycle, either loading the next job
//          or executing the current job
{
    currentTime++;                                          // INCREMENT THE TIME STEP
    
    if (!readyQueue.empty()) {                              // IF READY JOB IS AVAILABLE
        Job & currentJob = readyQueue.front();              //   GET THE NEXT JOB

        if (loadTimeRemaining > 0) {                        //   IF STILL LOADING, IDLE
            if (loadTimeRemaining == loadDelay) {
                cout << setw(4) << currentTime << ":   LOAD JOB " << currentJob.getID() 
                     << " (delay = " << loadDelay << ")" << endl;
            }
            loadTimeRemaining--;
        }
        else {                                              //   OTHERWISE, PROCESS
            if (sliceTimeRemaining == timeSlice) {          //     DISPLAY IF NEW JOB
                cout << setw(4) << currentTime << ":     START JOB " << currentJob.getID() 
                     << " (time remaining = " << currentJob.getRemainingTime() << ")" << endl;
            }

            JobStatus status = currentJob.execute();        //   EXECUTE THE JOB AND
            sliceTimeRemaining--;                           //   REDUCE ITS TIME SLICE

            if (status == DONE) {                           //   IF JOB FINISHED
                cout << setw(4) << currentTime+1 << ":       FINISH JOB " 
                     << currentJob.getID() << endl;
                readyQueue.pop();                           //     REMOVE FROM QUEUE AND
                sliceTimeRemaining = timeSlice;             //     RESET COUNTS
                loadTimeRemaining = loadDelay;

            }
            else if (sliceTimeRemaining == 0) {             //   IF TIME SLICE IS UP
                cout << setw(4) << currentTime+1 << ":       TIMEOUT JOB " 
                     << currentJob.getID() << endl;
                Job readyJob = currentJob;
                readyQueue.pop();                           //     MOVE TO BACK OF QUEUE
                readyQueue.push(readyJob);
                sliceTimeRemaining = timeSlice;             //       RESET TIME SLICE
                if (readyQueue.size() > 1) {                //       IF OTHER JOBS READY,
                    loadTimeRemaining = loadDelay;          //         RESET LOAD COUNT
                }
            }
        }
    }
}
