/*

A Queue is a data structure that uses the FIFO (First In, First Out) principle that allows
you enqueue a new value at the tail of the queue and dequeue the value at the head of the queue.
It also has functions to check if its full or empty.

This one is implemented with an array of a finite size with tail, head, and elements in
the queue tracked by variables outside the array.

*/




const int MAX_SIZE = 10;  // Define maximum queue size

int queue[MAX_SIZE];  // Array to hold the queue elements
int head = 0;  // Points to the front of the queue
int tail = -1; // Points to the rear of the queue
int count = 0; // Number of elements in the queue

// Function to check if the queue is full
bool isFull() {
  return count == MAX_SIZE;
}

// Function to check if the queue is empty
bool isEmpty() {
  return count == 0;
}

// Function to enqueue an element at the end
void enqueue(int value) {
  if (isFull()) {
    Serial.println("Queue is full. Cannot enqueue.");
  } else {
    tail = (tail + 1) % MAX_SIZE;
    queue[tail] = value;
    count++;
    Serial.print("Enqueued: ");
    Serial.println(value);
  }
}

// Function to dequeue an element from the front
int dequeue() {
  if (isEmpty()) {
    Serial.println("Queue is empty. Cannot dequeue.");
    return -1;  // Return -1 as an indicator of failure
  } else {
    int value = queue[head];
    head = (head + 1) % MAX_SIZE;
    count--;
    Serial.print("Dequeued: ");
    Serial.println(value);
    return value;
  }
}

void setup() {
  Serial.begin(9600);  // Start serial communication
}

void loop() {
  // Example usage
  enqueue(1);
  enqueue(2);
  enqueue(3);
  
  delay(1000);  // Wait 1 second

  dequeue();
  dequeue();

  delay(1000);  // Wait 1 second
}