#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "process.h"
#include "queue.h"

/*
 * Queue implementation
 * 5	4	3	2	1
 * START			END
 *
 * If you were to visualize the queue as a line, the end is the first person in line and the start is the last person in line
 * So when you enqueue, you are adding to the start of the line
 * And when you dequeue, you are exiting from the end of the line
 */

int contains(Queue *queue, char *username) {
    Process *current = queue->end;
    while (current != NULL) {
        if (strcmp(current->username, username) == 0) {
            return true;
        }
        current = current->prev_elem;
    }
    return false;
}

Process *search(Queue *queue, char *username) {
    Process *current = queue->end;
    while (current != NULL) {
        if (strcmp(current->username, username) == 0) {
            return current;
        }
        current = current->prev_elem;
    }
    return NULL;
}


void enqueue(Queue *queue, Process *process) {
	if (queue->end == NULL) { // If the queue is empty, set the start and end to the new process
		queue->end = process;
		queue->start = queue->end;
	} else {
		process->next_elem = queue->start; // Set the next element of the new process to the start of the queue
		queue->start->prev_elem = process; // Set the previous element of the start of the queue to the new process
		queue->start = process; // Set the start of the queue to the new process
	}
	queue->size++;
}

// WARNING: Returns a pointer to a process that is not in the queue, it is your responsibility to free it
Process *dequeue(Queue *queue) {
    if (queue->end == NULL) { // If the queue is empty, return NULL
        return NULL;
    }
    Process *temp = queue->end; // Store the end of the queue for returning later

    if (queue->size == 1) { // If the queue has one element, set the start and end to NULL
        queue->start = NULL;
        queue->end = NULL;
        queue->size--;
        return temp;
    }
	queue->end = queue->end->prev_elem; // Set the end to the previous element
    queue->end->next_elem = NULL; // Set the next element of the new end to NULL

	temp->prev_elem = NULL; // The dequeued element should not point to anything
	queue->size--;
	return temp;
}
void printList(Queue *queue) {
    Process *current = queue->end;
    while (current != NULL) {
        printf("%s\t%d\n", current->username, current->finish_time);
        current = current->prev_elem;
    }
}
int stop(Queue *queue) {
    Process *current = queue->end;
    while (current != NULL) {
        Process *next = current->prev_elem;
		destroyProcess(current);
        current = next;
    }
	free(queue);
    return true;
}

Queue *createQueue() {
	Queue *queue = calloc(1, sizeof(Queue));
	if (queue == NULL) {
		printf("Error allocating memory for queue\n");
		exit(EXIT_FAILURE);
	}
	queue->start = NULL;
	queue->end = NULL;
	queue->size = 0;
	return queue;
}

