#include "priority.h"
#include "main.h"
#include <stdlib.h>

void priority_run(process processes[], int num_processes, int aging) {
  process *ready_queue[num_processes];
  int num_ready = 0;
  int num_processed = 0;
  int num_run = 0;
  cpu_time_t next_free = 0;
  while (num_run < num_processes) {
    // Add new arrivals to ready queue
    for (int i = num_processed;
         i < num_processes && processes[i].arrival <= next_free; i++) {
      ready_queue[num_ready] = &processes[i];
      num_ready++;
      num_processed++;
    }

    // Idle if ready queue is empty
    if (num_ready == 0) {
      next_free = processes[num_processed].arrival;
      continue;
    }

    // Remove process with highest priority (FCFS if same priority)
    int next_i = 0;
    for (int i = 0; i < num_ready; i++) {
      if (ready_queue[i]->priority > ready_queue[next_i]->priority ||
          ready_queue[i]->priority == ready_queue[next_i]->priority) {
        next_i = i;
      }
    }
    process *next = ready_queue[next_i];
    num_ready--;
    for (int i = next_i; i < num_ready; i++) {
      ready_queue[i] = ready_queue[i + 1];
    }

    // Age processes (increase priority by 1)
    if (aging) {
      for (int i = 0; i < num_ready; i++) {
        ready_queue[i]->priority++;
      }
    }

    // Run process
    next->num_schedules = 1;
    next->starts = malloc(sizeof(cpu_time_t));
    next->starts[0] = next_free;
    next->durations = malloc(sizeof(cpu_time_t));
    next->durations[0] = next->burst;
    num_run++;

    next_free = next->starts[0] + next->burst;
  }
}

void priority_run_no_aging(process processes[], int num_processes) {
  priority_run(processes, num_processes, 0);
}

void priority_run_aging(process processes[], int num_processes) {
  priority_run(processes, num_processes, 1);
}

scheduler priority = (scheduler){.name = "priority",
                                 .description = NULL,
                                 .run = priority_run_no_aging,
                                 .uses_priority = 1};

scheduler priority_aging = (scheduler){.name = "priorityaging",
                                       .description = "Priority - With Aging",
                                       .run = priority_run_aging,
                                       .uses_priority = 1};
