#pragma once

// From: https://www.techiedelight.com/queue-implementation-using-templates-cpp/

#include <stdint.h>
#include <array>
#include <iostream>

#include "FIFORecordTemplates.hpp"

template<class RECORD_STRUCT, uint32_t depth>
	class FIFO_T
	{
	public:
		FIFO_T()
		{
			head = 0;
			tail = -1;
			count = 0;
			capacity = depth;
		}
				
		int32_t dequeue(RECORD_STRUCT &deQRecord)
		{
			// check for queue underflow
			if (isEmpty())
			{
				std::cout << qName << " FIFO empty" << std::endl;
				return (-1);
			}
			else
			{
				deQRecord = fifoRecords[head];
	
				head = (head + 1) % capacity;
				count--;
				return (count);
			}
		}
		
		int32_t enqueue(RECORD_STRUCT enQRecord)
		{
			// check for queue overflow
			if (isFull())
			{
				std::cout << "OverFlow\nQueue Overflow, nothing queued\n" << std::endl;
				return -1;
			}
			else
			{
				tail = (tail + 1) % capacity;

				fifoRecords[tail] = enQRecord;
				count++;
				return count;
			}
		}
	
		int getCount()
		{
			return count;
		}		
		
		void clearFIFO()
		{
			head = 0;
			tail = -1;
			count = 0;
		}
		
	protected:
		uint32_t capacity; // maximum capacity of the queue
		int32_t head; // points to front element in the queue (if any)
		int32_t tail; // points to last element in the queue
		int32_t count; // current size of the queue
		std::string qName;
		
	private:
		std::array<RECORD_STRUCT, depth> fifoRecords;
		
		bool isFull()
		{
			return (getCount() == capacity);
		}

		// Utility function to check if the queue is empty or not
		bool isEmpty()
		{
			return (getCount() <= 0);
		}
	};
