#include <stdio.h>
#include "lib/queue.h"

#define MAX_USERNAME_LENGTH 100
int QUANTUM;

Queue *input_queue() {
    Queue *queue = createQueue();
    char username[MAX_USERNAME_LENGTH]; // username buffer
    char job;
    int arrival_time, duration;

    scanf("%d", &QUANTUM);
    while (getchar() != '\n'); // clear the newline from the buffer
    while (getchar() != '\n'); // ignore the rest of the line, this is the table line

    // Loop through the process table and enqueue each process
    while (scanf("%99s %c %d %d", username, &job, &arrival_time, &duration) != EOF) {
        Process *process = createProcess(username, job, arrival_time, duration);
        enqueue(queue, process);
    }
    return queue;
}


void simulation(Queue *in_queue) {
    // Summary creation
    Process *process = in_queue->end;
    Queue *summary_queue = createQueue();
    for (int i = 0; i < in_queue->size; ++i) {
        if (contains(summary_queue, process->username) == false) {
            Process *copy = createProcess(process->username, process->job, process->arrival_time, process->duration);
            enqueue(summary_queue, copy);
        }
        process = process->prev_elem;
    }

    // Loop variables
    int quantum = QUANTUM;
    int addedJobs = 0;
    int time = 0;

    // Create a queue for the simulation
    Queue *sim_queue = createQueue();

    printf("Time\tJob\n");
    while (true) {
        time++;
        // Begin going through all jobs and enqueueing them if they have arrived
        process = in_queue->end;
        for (int i = 0; i < in_queue->size; i++) {
            if (process->arrival_time == time) {
                // Create copy to keep the queues separate
                Process *copy = createProcess(process->username, process->job, process->arrival_time, process->duration);
                enqueue(sim_queue, copy);
                addedJobs++;
            }
            process = process->prev_elem;
        }

        // Begin printing the current job
        process = sim_queue->end;
        if (sim_queue->size == 0) { //If there is nothing in sim_queue, print "-"
            printf("%d\t-\n", time);
            if (addedJobs == in_queue->size) {
                break; // If all jobs have been added, and the simulation queue is empty, then we are done
            }
        } else {
            printf("%d\t%c\n", time, process->job); // Print the current job
            process->duration--;
            quantum--;
            if (process->duration == 0) { // If the process is done, delete it
                Process *temp = dequeue(sim_queue); // Store the process in a temp variable for deletion
                search(summary_queue, temp->username)->finish_time = time; // Set the finish time for the summary queue
                destroyProcess(temp); // This should be called on every process
                quantum = QUANTUM; // Make sure to reset the quantum when a process is done
            } else if (quantum == 0) { // If the quantum is 0, then we need to dequeue the process and enqueue it again
                process = dequeue(sim_queue);
                enqueue(sim_queue, process);
                quantum = QUANTUM;
            }
        }
    }

    // Print the summary
    printf("\nSummary\n");
    printList(summary_queue);

    // Free memory for the simulation queue. There should be nothing left in it
    stop(sim_queue);

    // We never dequeue from the summary queue, so we don't need to make sure about freeing dequeued processes
    stop(summary_queue);
}

int main() {
    Queue *in_queue = input_queue(); // Create the input queue
    simulation(in_queue); // Run simulation on input queue
    stop(in_queue); // Free memory for input queue
    return 0;
}
