using System;
using Microsoft.SPOT;

using System.Text;
using System.Threading;
using System.IO.Ports;

using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.IO;

namespace CPF
{
    class FLBB
    {
        private static SerialPort FLBBPort = new SerialPort("COM5", 19200, Parity.None, 8, StopBits.One);

        private static StringBuilder sbTemp = new StringBuilder(256);

        private static StructQueue.qStruct qS = new StructQueue.qStruct();

        public static void init()
        {
            qS.byteArray = new byte[StructQueue.byteArrayWidth];

            FLBBPort.ReadTimeout = 5000;
            FLBBPort.Open();

            FLBBPort.DiscardInBuffer();
            FLBBPort.DiscardOutBuffer();
            FLBBPort.DataReceived += new SerialDataReceivedEventHandler(FLBBDataReceived);

            //Debug.Print("sending FLBB stop command");
            sendStopCmd();
            Thread.Sleep(1000);
            //Debug.Print("sending FLBB pkt command");
            sendPktCmd(configFile.flbbPkt);
            Thread.Sleep(1000);
            //Debug.Print("sending FLBB ave command");
            sendAveCmd(configFile.flbbAve);
        }

        private static byte[] txBytes = new byte[64];
        private static StringBuilder pktCmd = new StringBuilder("$pkt ");
        private const string pktCmdHeader = "Sending FLBB pkt command";

        private static void sendPktCmd(int numPkt)
        {
            //Debug.Print("Sending FLBB pkt command");

            sbTemp.Clear();
            sbTemp.Append(pktCmdHeader);
            sbTemp.Append(": ");
            sbTemp.Append(pktCmd);
            sbTemp.AppendLine(numPkt.ToString());
            Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(sbTemp.ToString()), qS.byteArray, sbTemp.Length);
            qS.state = Program.CurrentState;
            qS.qRecordType = StructQueue.QRecordType.FLBB;
            qS.timeStamp = DateTime.Now;
            Program.sQueue.Enqueue(qS);

            sbTemp.Clear();
            sbTemp.Append(pktCmd);
            sbTemp.AppendLine(numPkt.ToString());
            Array.Clear(txBytes, 0, txBytes.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(sbTemp.ToString()), txBytes, sbTemp.Length);
            FLBBPort.Write(txBytes, 0, sbTemp.Length);
        }

        private static StringBuilder aveCmd = new StringBuilder("$ave ");
        private const string aveCmdHeader = "Sending FLBB ave command";

        private static void sendAveCmd(int numAve)
        {
            //Debug.Print("Sending FLBB ave command");

            sbTemp.Clear();
            sbTemp.Append(aveCmdHeader);
            sbTemp.Append(": ");
            sbTemp.Append(aveCmd);
            sbTemp.AppendLine(numAve.ToString());

            Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(sbTemp.ToString()), qS.byteArray, sbTemp.Length);
            qS.state = Program.CurrentState;
            qS.qRecordType = StructQueue.QRecordType.FLBB;
            qS.timeStamp = DateTime.Now;
            Program.sQueue.Enqueue(qS);

            sbTemp.Clear();
            sbTemp.Append(aveCmd);
            sbTemp.AppendLine(numAve.ToString());
            Array.Clear(txBytes, 0, txBytes.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(sbTemp.ToString()), txBytes, sbTemp.Length);
            FLBBPort.Write(txBytes, 0, sbTemp.Length);
        }

        private static readonly byte[] stopCmd = UTF8Encoding.UTF8.GetBytes("!!!!!!!!!!!!!!!");
        private const string stopCmdHeader = "Sending FLBB stop command";

        private static void sendStopCmd()
        {
            //Debug.Print("Sending FLBB stop command");
            Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(stopCmdHeader), qS.byteArray, stopCmdHeader.Length);
            qS.state = Program.CurrentState;
            qS.qRecordType = StructQueue.QRecordType.FLBB;
            qS.timeStamp = DateTime.Now;
            Program.sQueue.Enqueue(qS);

            FLBBPort.Write(stopCmd, 0, stopCmd.Length);
        }

        private static readonly byte[] runCmd = UTF8Encoding.UTF8.GetBytes("$run\r\n");
        private const string runCmdHeader = "Sending FLBB run command";

        public static int sendRunCmd()
        {
            //Debug.Print("Sending FLBB run command");
            Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
            Array.Copy(UTF8Encoding.UTF8.GetBytes(runCmdHeader), qS.byteArray, runCmdHeader.Length);
            qS.state = Program.CurrentState;
            qS.qRecordType = StructQueue.QRecordType.FLBB;
            qS.timeStamp = DateTime.Now;
            Program.sQueue.Enqueue(qS);

            FLBBPort.Write(runCmd, 0, runCmd.Length);

            return (1);
        }

        private const int ehBufferSize = 2048;
        private static byte[] bytesRead = new byte[ehBufferSize];
        private static byte[] messageBytes = new byte[ehBufferSize];

        private static byte STX = (byte)'/';
        private static byte ETX = (byte)'\n';
        private static int bytesToRead;
        private static int messageIndex = 0;
        private static int messageNum = 0;

        private static readonly byte[] errorHeader = UTF8Encoding.UTF8.GetBytes("Error: FLBB EH Message Overrun");

        private static void FLBBDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            bytesToRead = FLBBPort.BytesToRead;

            if ((bytesToRead + messageIndex + 50) < ehBufferSize)
            {
                try
                {
                    FLBBPort.Read(bytesRead, 0, bytesToRead);
                }
                catch
                {
                    Debug.Print("FLBB Read Exception");          //TODO do something smarter here
                }

                for (int i = 0; i < bytesToRead; i++)
                {
                    messageBytes[messageIndex] = bytesRead[i];
                    if (messageIndex == 0)      //Check to make sure first character is = LF
                    {
                        if (messageBytes[0] == STX)  //only move on to byte index 1 after we get a LF
                            messageIndex = messageIndex + 1;
                    }
                    if (messageBytes[messageIndex] == ETX)
                    {
                        qS.timeStamp = DateTime.Now;
                        qS.state = Program.CurrentState;

                        //sbTemp.Clear();
                        //sbTemp.Append(UTF8Encoding.UTF8.GetChars(messageBytes, 0, messageIndex - 1));
                        //Debug.Print("FLBB Message = " + sbTemp.ToString());

                        Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
                        Array.Copy(messageBytes, qS.byteArray, messageIndex - 1);
                        qS.qRecordType = StructQueue.QRecordType.FLBB;
                        Program.sQueue.Enqueue(qS);

                        messageNum = messageNum + 1;
                        messageIndex = 0;
                        Array.Clear(messageBytes, 0, messageBytes.Length);
                    }
                    else
                    {
                        messageIndex = messageIndex + 1;
                    }
                }
            }
            else
            {
                //ErrorHandler.incrFLBBEHErrors();

                Array.Clear(qS.byteArray, 0, qS.byteArray.Length);
                Array.Copy(errorHeader, qS.byteArray, errorHeader.Length);
                Array.Copy(messageBytes, qS.byteArray, (messageIndex - 1));
                qS.timeStamp = DateTime.Now;
                qS.state = Program.CurrentState;
                qS.qRecordType = StructQueue.QRecordType.FLBB;
                Program.sQueue.Enqueue(qS);
            }
        }
    }
}
