using System;
using System.Runtime.CompilerServices;

namespace SWModules
{
    public delegate void ProcessMessage(QRecord qRecord);

    public enum QRecordType : int
    {
        Optode = 0,
        SBE41,
        FLBB,
        OCR,
        ADC,
        PTH,
        InstrumentHandler,
        BTConsole,
        EVK7,
        IModem,
        StructQueue,
        WriteLog,
        PositionReport,
        MT_MessageArrived,
        FileReceived,
        FileSent,
        PH,
        NO3,
        MSC,
        Elmo,
        Unknown,
        Error
    }

    public struct QRecord
    {
        public ProcessMessage processMessage;
        public QRecordType type;
        public int errorCode;
        public DateTime timeStamp;
        public CPFStates state;
        public byte[] byteArray;
        public int length;

        public void Update()
        {
            timeStamp = DateTime.Now;
            state = SV.CurrentState;
        }

        public QRecord(int width, ProcessMessage pmsg)
        {
            byteArray = new byte[width];
            length = -1;
            processMessage = pmsg;
            errorCode = 0;
            timeStamp = DateTime.Now;
            state = SV.CurrentState;
            type = QRecordType.Unknown;
        }

        public QRecord(ProcessMessage pmsg)
            : this(MessageQueue.width, pmsg)
        {
        }


    }

    public abstract class FIFOQueue
    {

        private int qDepth;
        public int qWidth;

        private int head = 0;
        private int tail = 0;
        protected int count = 0;

        protected QRecord qEntry;

        private QRecord[] queue;

        public FIFOQueue(int depth, int width)
        {
            qDepth = depth;
            qWidth = width;

            queue = new QRecord[qDepth];
            for (int i = 0; i < qDepth; i++)
                queue[i].byteArray = new byte[qWidth];

            head = 0;
            tail = 0;
            count = 0;
        }

        public abstract void processQ();
        public abstract void processQ(TimeSpan startTime, TimeSpan period);
        public abstract void processQ(int maxMessages);

        public int Count
        {
            get { return count; }
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Enqueue(QRecord entry)
        {
            if (count >= qDepth) return;

            queue[head].processMessage = entry.processMessage;
            queue[head].timeStamp = entry.timeStamp;
            queue[head].state = entry.state;
            queue[head].type = entry.type;
            queue[head].errorCode = entry.errorCode;
            queue[head].length = entry.length;
            Array.Copy(entry.byteArray, queue[head].byteArray, entry.byteArray.Length);

            head = (head + 1) % qDepth;
            count++;
        }

        private QRecord returnQEntry;
        [MethodImpl(MethodImplOptions.Synchronized)]
        public QRecord Dequeue()
        {
            if (count == 0) {
                throw new InvalidOperationException("Trying to dequeue from empty queue");
            }
            returnQEntry = queue[tail];

            tail = (tail + 1) % qDepth;
            count--;
            return returnQEntry;
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Clear()
        {
            count = 0; 
        }

    }
}
