using System;
using Microsoft.SPOT;

using System.Text;
using HWModules;
using SWModules;

namespace CPF
{
    //TODO P1 Really need to implement this
    abstract public class CommandHandler
    {
        public struct CommandResponse
        {
            public byte[] command;
            public byte[] response;
            public int maxRetries;
            public TimeSpan retryPeriod;
            public delegate void commandProcessor();
        }
       
        abstract protected void defineCommandResponses();
        
        protected static NativeUART baseIOPort;

        public CommandHandler(NativeUART inPort)
        {
            baseIOPort = inPort;
        }

        protected static int numTrys = 0;
        protected static bool waitingForResponse = false;
        protected static DateTime CRStartTime = new DateTime();
        protected static CommandResponse currentCR = new CommandResponse();

        private static StringBuilder sbTemp = new StringBuilder(64);
        protected static byte[] parsedResponse = new byte[MessageQueue.width];

        public int sendCommand(CommandResponse cr, bool wait)
        {
            if (!waitingForResponse)
            {
                //send the command
                currentCR = cr;
                sbTemp.Clear();
                sbTemp.Append("Writing command: ");
                sbTemp.Append(SafeEncoding.GetChars(cr.command));
                EngrLogger.writeToColumns(sbTemp);

                baseIOPort.Write(cr.command, 0, cr.command.Length);

                if (wait)
                {
                    waitingForResponse = true;
                    CRStartTime = DateTime.Now;
                    numTrys = 0;
                }
                return 0;
            }
            else
            {
                if (cr.command != currentCR.command)
                {
                    sbTemp.Clear();
                    sbTemp.Append("Requesting new command: ");
                    sbTemp.Append(cr.command);
                    sbTemp.Append("before previous command: ");
                    sbTemp.Append(currentCR.command);
                    sbTemp.Append("completed ");
                    EngrLogger.writeToColumns(sbTemp);
                    return -1;
                }
                else
                {
                    //check response 
                    if (parsedResponse.Length >= currentCR.response.Length)
                    {
                        if (GHI.Utilities.Arrays.Contains(parsedResponse, 0, currentCR.response, 0, currentCR.response.Length) >= 0)
                        {
                            sbTemp.Clear();
                            sbTemp.Append("Got correct response: ");
                            sbTemp.Append(SafeEncoding.GetChars(parsedResponse));
                            EngrLogger.writeToColumns(sbTemp);

                            //TODO still need to figure out how to make this work 
                            //currentCR.commandProcessor;
                            
                            waitingForResponse = false;
                            Array.Clear(parsedResponse, 0, parsedResponse.Length);

                            return 1;
                        }
                    }

                    if ((DateTime.Now - CRStartTime) > currentCR.retryPeriod)
                    {
                        numTrys++;
                        sbTemp.Clear();
                        sbTemp.Append(SafeEncoding.GetChars(currentCR.command));
                        sbTemp.Append(" Retry num: ");
                        sbTemp.Append(numTrys.ToString());
                        EngrLogger.writeToColumns(sbTemp);

                        if (numTrys > currentCR.maxRetries)
                        {
                            sbTemp.Clear();
                            sbTemp.Append(SafeEncoding.GetChars(currentCR.command));
                            sbTemp.Append(" Exceeded max number of retries");
                            EngrLogger.writeToColumns(sbTemp);

                            waitingForResponse = false;
                            Array.Clear(parsedResponse, 0, parsedResponse.Length);

                            return -1;
                        }
                    }
                }
                return 0;
            }
        }
     
    }
}
