using System;
using Microsoft.SPOT;

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

using System.Text;
using System.IO;

using GHI.Premium.IO;

namespace miniCPF
{
    class Logger
    {
        private static PersistentStorage sdCard = new PersistentStorage("SD");

        private static FileStream logFile;

        private static DateTime timeNow;

        private static StringBuilder fileName = new StringBuilder(256);
        private static StringBuilder sb = new StringBuilder(256);

        private static byte[] tempQueueArray = new byte[256];

        private static byte[] outMessage = new byte[256];

        private static char[] tempCharArray = new char[512];

        private static object loggerLock = new object();

        public enum ColumnNums : int
        {
            depth=0,
            platformVelocity,
            setpoint,
            JV,
            lat,
            lon,
            lastColumn,
        }

        private const byte tab = 9;
        private const byte comma = 44;
        private const byte CR = 13;
        private const byte LF = 10;
        public const byte token = comma;

        private static int tabIndex;
        private static int LFIndex;
        private static int tabCounter;
        private static int numValueArrayBytes;
        private static int i;

        private static int endOfCommentIndex = 0;

        private static VolumeInfo sdVol;

        public static void init()
        {
            sdCard.MountFileSystem();
            sdVol = new VolumeInfo("SD");

            sb.Clear();
            sb.Append("Volume Total Size:     ");
            sb.Append(sdVol.TotalSize.ToString());
            lock (loggerLock) { Program.MessageQueue.Enqueue(Logger.getNewLogArrayHeader(UTF8Encoding.UTF8.GetBytes(sb.ToString()))); }

            sb.Clear();
            sb.Append("Volume Free Space:     ");
            sb.Append(sdVol.TotalFreeSpace.ToString());
            lock (loggerLock) { Program.MessageQueue.Enqueue(Logger.getNewLogArrayHeader(UTF8Encoding.UTF8.GetBytes(sb.ToString()))); }

            timeNow = DateTime.Now;

            fileName.Clear();
            fileName.Append(sdVol.RootDirectory);
            fileName.Append("\\");
            fileName.Append(timeNow.Year.ToString());
            fileName.Append("-");
            fileName.Append(timeNow.Month.ToString());
            fileName.Append("-");
            fileName.Append(timeNow.Day.ToString());
            fileName.Append("T");
            fileName.Append(timeNow.Hour.ToString());
            fileName.Append("-");
            fileName.Append(timeNow.Minute.ToString());
            fileName.Append("-");
            fileName.Append(timeNow.Second.ToString());

            logFile = new FileStream(fileName.ToString(), FileMode.OpenOrCreate, FileAccess.Write);
            sb.Clear();
            sb.Append("File Name = ");
            sb.Append(fileName.ToString());
            lock (loggerLock) { Program.MessageQueue.Enqueue(Logger.getNewLogArrayHeader(UTF8Encoding.UTF8.GetBytes(sb.ToString()))); }
        }

        public static byte[] getNewLogArrayHeader(byte[] comment)
        {
            timeNow = DateTime.Now;
            Array.Clear(tempQueueArray, 0, tempQueueArray.Length);

            sb.Clear();
            sb.Append(timeNow.ToString());

            // Year/Month/Day token
            for (int i = 6; i < 10; i++)
                tempQueueArray[i - 6] = (byte)sb[i];
            tempQueueArray[4] = (byte)'/';
            for (i = 0; i < 2; i++)
                tempQueueArray[i + 5] = (byte)sb[i];
            tempQueueArray[7] = (byte)'/';
            for (i = 3; i < 5; i++)
                tempQueueArray[i + 5] = (byte)sb[i];
            tempQueueArray[10] = token;

            // Hour:Minute:Second token
            for (i = 11; i < 19; i++)
                tempQueueArray[i] = (byte)sb[i];
            tempQueueArray[19] = token;

            // Add in comment
            //trim off the trailing empty array elements  
            //Note: comment array must be (byte)characters for this to work
            endOfCommentIndex = Array.IndexOf(comment, 0);
            if (endOfCommentIndex >= 0)
            {
                Array.Copy(comment, 0, tempQueueArray, 20, endOfCommentIndex);
                tempQueueArray[20 + endOfCommentIndex] = token;
                Array.Copy(Program.stateName[(int)Program.CPFState], 0, tempQueueArray, (21 + endOfCommentIndex), Program.stateName[(int)Program.CPFState].Length);
            }
            else
            {
                Array.Copy(comment, 0, tempQueueArray, 20, comment.Length);
                tempQueueArray[20 + comment.Length] = token;
                Array.Copy(Program.stateName[(int)Program.CPFState], 0, tempQueueArray, (21 + comment.Length), Program.stateName[(int)Program.CPFState].Length);
            }
            //tempCharArray = UTF8Encoding.UTF8.GetChars(tempQueueArray);

            return tempQueueArray;
        }

        public static byte[] addPair(ColumnNums columnNum, byte[] valueByteArray, byte[] inMessage)
        {
            tabIndex = 0;
            LFIndex = -1;
            tabCounter = 0;

            //find the index of the desired token
            while (tabCounter != (int)columnNum)
            {
                if (inMessage[tabIndex] == token)
                    tabCounter = tabCounter + 1;
                tabIndex = tabIndex + 1;
            }
            tabIndex = tabIndex + 1;    //Column numbers start at 0 and don't include the token between data and time

            //find the index of the terminating LF
            LFIndex = Array.IndexOf(inMessage, LF, 0);
            numValueArrayBytes = Array.IndexOf(valueByteArray, 0, 0);

            //Clear the out message
            Array.Clear(outMessage, 0, outMessage.Length);
            
            //Copy everything in the in message up to the desired token into out message
            Array.Copy(inMessage, 0, outMessage, 0, tabIndex);
            sb.Clear();
            sb.Append(UTF8Encoding.UTF8.GetChars(outMessage));
            Debug.Print(sb.ToString());
            
            //Copy the value into out message after the desired token
            Array.Copy(valueByteArray, 0, outMessage, tabIndex, numValueArrayBytes);
            sb.Clear();
            sb.Append(UTF8Encoding.UTF8.GetChars(outMessage));
            Debug.Print(sb.ToString());
            
            //Copy everything in the in message after the desired token into out message after the value byte array
            Array.Copy(inMessage, tabIndex + 1, outMessage, tabIndex + numValueArrayBytes, LFIndex - tabIndex);
            sb.Clear();
            sb.Append(UTF8Encoding.UTF8.GetChars(outMessage));
            Debug.Print(sb.ToString());

            return outMessage;
        }

        private static void printVolInfo()
        {
            sb.Clear();
            sb.Append("Volume Total Size:     ");
            sb.Append(sdVol.TotalSize.ToString());
            lock (loggerLock) { Program.MessageQueue.Enqueue(Logger.getNewLogArrayHeader(UTF8Encoding.UTF8.GetBytes(sb.ToString()))); }

            sb.Clear();
            sb.Append("Volume Free Space:     ");
            sb.Append(sdVol.TotalFreeSpace.ToString());
            lock (loggerLock) { Program.MessageQueue.Enqueue(Logger.getNewLogArrayHeader(UTF8Encoding.UTF8.GetBytes(sb.ToString()))); }
 
            //String[] fileNames = Directory.GetFiles(sdVol.RootDirectory);
            //for (int i = 0; i < fileNames.Length; i++)
            //{
            //    FileInfo fileInfo = new FileInfo(fileNames[i]);
            //    Debug.Print(i.ToString() + "  File name: " + fileNames[i]
            //                + "   Creation Date = " + fileInfo.CreationTime.ToString()
            //                + "  Length = " + fileInfo.Length.ToString());
            //}
        }

        public static void writeLogMessage(byte[] writeMessage)
        {
            logFile.Write(writeMessage, 0, writeMessage.Length);
        }

        public static void close()
        {
            logFile.Close();
        }

        public static void unMount()
        {
            sdCard.UnmountFileSystem();
        }
    }
}
