using System;
using System.Text;
using System.IO;

using LFP_Manager.DataStructure;

namespace LFP_Manager.Utils
{
    class csLog
    {
        private static string SYSTEMLOG_FILE_DIR_M = "\\log\\systemlog";
        private static string SYSTEMLOG_FILE_DIR = "\\log\\systemlog";

        public static string GetLogFolder(string AppPath)
        {
            string path = System.IO.Path.GetDirectoryName(AppPath);

            if (Directory.Exists(path + SYSTEMLOG_FILE_DIR_M) == false)
                Directory.CreateDirectory(path + SYSTEMLOG_FILE_DIR_M);

            return path + SYSTEMLOG_FILE_DIR_M;
        }

        public static void SystemErrorLog(CommConfig sConfig, string sEvent, DateTime aTime, string AppPath)
        {
            SYSTEMLOG_FILE_DIR = string.Format("{0}\\SystemErr\\{1}", "\\log", string.Format("{0:yyyyMM}", aTime));
            string path = Path.GetDirectoryName(AppPath);
            string FileName = string.Format(path + SYSTEMLOG_FILE_DIR + "\\{0}_SYS_ERROR_LOG.txt", string.Format("{0:yyMMdd}", aTime));
            byte[] logData;

            if (Directory.Exists(path + SYSTEMLOG_FILE_DIR) == false)
            {
                Directory.CreateDirectory(path + SYSTEMLOG_FILE_DIR);
            }

            FileStream logFile;
            if (File.Exists(FileName) == false)
            {
                logFile = new FileStream(FileName, FileMode.CreateNew, FileAccess.ReadWrite);
                logFile.Close();
            }

            logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

            if (logFile != null)
            {
                logFile.Seek(0, SeekOrigin.End);
                logData = WriteEventData(aTime, sEvent);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }
        }

        private static byte[] WriteEventData(DateTime aLog, String sEvent)
        {
            string tt;
            string sdata;

            tt = aLog.ToString("yyyy-MM-dd HH:mm:ss");
            sdata = String.Format(
                "{0}    {1}\r\n"
                , tt                                                                                    // 0    DATETIME 
                , sEvent                                                                                // 1    Event Log Data 
                );

            Byte[] info =
                   new UTF8Encoding(true).GetBytes(sdata);

            return info;
        }


        public static void SystemDataLog(int RackID, ref CommConfig sConfig, ref DeviceSystemData sData, DateTime aTime, string AppPath)
        {
            SYSTEMLOG_FILE_DIR = String.Format("{0}\\SHELF{1}\\{2}", "\\log\\systemlog", RackID, String.Format("{0:yyyyMM}", aTime));

            FileStream logFile = null;
            string path = System.IO.Path.GetDirectoryName(AppPath);
            string FileName = String.Format(path + SYSTEMLOG_FILE_DIR + "\\SHELF{0}_LOG_{1}.csv", RackID, String.Format("{0:yyMMdd}", aTime));
            byte[] logData;

            if (Directory.Exists(path + SYSTEMLOG_FILE_DIR) == false)
                Directory.CreateDirectory(path + SYSTEMLOG_FILE_DIR);

            if (File.Exists(FileName) == false)
            {
                logFile = new FileStream(FileName, FileMode.CreateNew, FileAccess.ReadWrite);
                logData = WriteDataHeader(aTime);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }

            logFile = null;
            //logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite);
            logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

            if (logFile != null)
            {
                logFile.Seek(0, SeekOrigin.End);
                logData = WriteData(aTime, sConfig, sData);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }
        }

        public static void SystemTotalDataLog(CommConfig sConfig, DeviceSystemTotalData tData, DateTime aTime, string AppPath, string LogFileName)
        {
            SYSTEMLOG_FILE_DIR = String.Format("{0}\\MAIN\\{1}", "\\log\\systemlog", String.Format("{0:yyyyMM}", aTime));

            FileStream logFile = null;
            string path = System.IO.Path.GetDirectoryName(AppPath);
            //string FileName = String.Format(path + SYSTEMLOG_FILE_DIR + "\\SHELF{0}_LOG_{1}.csv", RackID, String.Format("{0:yyMMdd}", aTime));
            string FileName = String.Format(path + SYSTEMLOG_FILE_DIR + "\\MAIN_LOG_{0}.csv", LogFileName);
            byte[] logData;

            if (Directory.Exists(path + SYSTEMLOG_FILE_DIR) == false)
                Directory.CreateDirectory(path + SYSTEMLOG_FILE_DIR);

            if (File.Exists(FileName) == false)
            {
                logFile = new FileStream(FileName, FileMode.CreateNew, FileAccess.ReadWrite);
                logData = WriteTotalDataHeader(aTime);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }

            logFile = null;
            //logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite);
            logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

            if (logFile != null)
            {
                logFile.Seek(0, SeekOrigin.End);
                logData = WriteTotalData(aTime, sConfig, tData);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }
        }

        public static void SystemDataLog(int RackID, CommConfig sConfig, DeviceSystemData sData, DateTime aTime, string AppPath, string LogFileName)
        {
            SYSTEMLOG_FILE_DIR = String.Format("{0}\\SHELF{1}\\{2}", "\\log\\systemlog", RackID, String.Format("{0:yyyyMM}", aTime));

            FileStream logFile = null;
            string path = System.IO.Path.GetDirectoryName(AppPath);
            //string FileName = String.Format(path + SYSTEMLOG_FILE_DIR + "\\SHELF{0}_LOG_{1}.csv", RackID, String.Format("{0:yyMMdd}", aTime));
            string FileName = String.Format(path + SYSTEMLOG_FILE_DIR + "\\SHELF{0}_LOG_{1}.csv", RackID, LogFileName);
            byte[] logData;

            if (Directory.Exists(path + SYSTEMLOG_FILE_DIR) == false)
                Directory.CreateDirectory(path + SYSTEMLOG_FILE_DIR);

            if (File.Exists(FileName) == false)
            {
                logFile = new FileStream(FileName, FileMode.CreateNew, FileAccess.ReadWrite);
                logData = WriteDataHeader(aTime);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }

            logFile = null;
            //logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite);
            logFile = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

            if (logFile != null)
            {
                logFile.Seek(0, SeekOrigin.End);
                logData = WriteData(aTime, sConfig, sData);
                logFile.Write(logData, 0, logData.Length);
                logFile.Close();
            }
        }

        public static void MakeCosoleStrLog(CommConfig cConfig, string log)
        {
            DateTime aDate = DateTime.Now;
            string mSN = "";
            if ((cConfig.mSN == null) || (cConfig.mSN == ""))
            {
                mSN = String.Format("00000000");
            }
            else
            {
                mSN = cConfig.mSN;
            }

            string filename = string.Format("{0}_CB_TEST_{1:yyMMddHH}.log", mSN, aDate);
            string filepath =
                Path.GetDirectoryName(cConfig.AppPath)
                + String.Format(@"\test\{0:yyMMdd}\", aDate)
                + filename;

            if (Directory.Exists(Path.GetDirectoryName(filepath)) == false)
                Directory.CreateDirectory(Path.GetDirectoryName(filepath));

            string strlog = log;
            string flog = String.Format("[{0:yyyy-MM-dd HH:mm:ss}]: {1}\r\n", aDate, strlog);
            byte[] bLog = Encoding.UTF8.GetBytes(flog);
            FileStream logFile = null;

            if (File.Exists(filepath) == false)
            {
                logFile = new FileStream(filepath, FileMode.CreateNew, FileAccess.ReadWrite);
                logFile.Seek(0, SeekOrigin.End);
                logFile.Write(bLog, 0, bLog.Length);
                logFile.Close();
            }
            else
            {
                logFile = new FileStream(filepath, FileMode.Open, FileAccess.ReadWrite);
                logFile.Seek(0, SeekOrigin.End);
                logFile.Write(bLog, 0, bLog.Length);
                logFile.Close();
            }
        }

        #region SYSTEM DATE LOGGING

        private static byte[] WriteTotalDataHeader(DateTime aDateTime)
        {
            string tt;
            string sdata;

            tt = aDateTime.ToString("yyyy-MM-dd HH:mm:ss");
            sdata = String.Format(
                "{0};{1};{2};{3};{4};{5};{6};{7};{8};{9};"
                , "DATETIME"                    // 0
                , "INTERFACE"                   // 1
                , "MODEL"                       // 2
                , "COMM STATUS"                 // 3
                , "STATUS"                      // 4
                , "ALARM"                       // 5
                , "VOLTAGE"                     // 6
                , "CURRENT"                     // 7
                , "SOC"                         // 8
                , "MAX. TEMP"                   // 9
               );
            sdata += "\r\n";

            Byte[] info =
                   new UTF8Encoding(true).GetBytes(sdata);

            return info;
        }

        private static byte[] WriteDataHeader(DateTime aDateTime)
        {
            string tt;
            string sdata;

            tt = aDateTime.ToString("yyyy-MM-dd HH:mm:ss");
            sdata = String.Format(
                "{0};{1};{2};{3};{4};{5};{6};{7};{8};"
                , "DATETIME"                    // 0
                , "INTERFACE"                   // 1
                , "MODEL"                       // 2
                , "COMM STATUS"                 // 3
                , "STATUS"                      // 4
                , "ALARM"                       // 5
                , "VOLTAGE"                     // 6
                , "CURRENT"                     // 7
                , "SOC"                         // 8
               );

            for (int i = 0; i < csConstData.SystemInfo.MAX_MODULE_CELL_SIZE; i++)
            {
                sdata += String.Format("{0},", String.Format("Cell_{0}", i + 1));
            }

            for (int i = 0; i < csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE; i++)
            {
                sdata += String.Format("{0},", String.Format("Temp_{0}", i + 1));
            }

            sdata += String.Format("{0},", String.Format("CPU_Temp"));

            sdata += String.Format(
                "{0};{1};{2};"
                , "Warning"                     // 0
                , "Fault"                        // 1
                , "cellBallanceStatus"          // 2
               );
            sdata += "\r\n";

            Byte[] info =
                   new UTF8Encoding(true).GetBytes(sdata);

            return info;
        }

        private static string GetStatusString(short aStatus)
        {
            string result = "";

            if (aStatus == 0)
            {
                result = "STANDBY";
            }
            else if (aStatus == 1)
            {
                result = "CHARGING";
            }
            else if (aStatus == 2)
            {
                result = "DISCHARGING";
            }
            else if (aStatus == 3)
            {
                result = "FLOATING";
            }
            else
            {
                result = "UNKNOWN";
            }
            return result;
        }

        private static string GetAlarmString(short aAlarm)
        {
            string result = "";
            bool[] rackStatus = csUtils.Int16ToBitArray(aAlarm);

            if (aAlarm == 0)      result = "NORMAL";
            else if (aAlarm == 1) result = "WARNING";
            else if (aAlarm == 2) result = "FAULT";
            else if (aAlarm == 3) result = "WARMING UP";
            else                  result = "UNKNOWN";

            return result;
        }

        private static string GetInterface(int sCommType)
        {
            string result = "";

            if (sCommType == 0)      result = "SNMP";
            else if (sCommType == 1) result = "UART";
            else                     result = "CAN";

            return result;
        }

        private static string GetModelName(CommConfig sConfig)
        {
            string result = "";

            if (sConfig.CommType == 0)
            {
                // SNMP
                switch (sConfig.SnmpModelIndex)
                {
                    case 0: result = "LFPS-4850"; break;
                    case 1: result = "LFPS-4870"; break;
                    case 2: result = "LFPS-48100"; break;
                    case 3: result = "LFPR-48300"; break;
                    case 4: result = "LFPR-48600"; break;
                    case 5: result = "LFPR-48900"; break;
                    case 6: result = "LFPR-481000H"; break;
                }
            }
            else if (sConfig.CommType == 1)
            {
                // UART
                switch (sConfig.UartModelIndex)
                {
                    case 0: result = "LFPS-48150"; break;
                }
            }
            else
            {
                // CAN
                result = "LFPS-48100H";
            }

            return result;
        }

        private static string GetCommStatus(CommConfig sConfig, DeviceSystemData sData)
        {
            string result = "";

            if (sConfig.CommType == 0)
            {
                // SNMP
                if (sData.CommFail == false)
                {
                    if (sData.ShelfCommFail == false) result = "NORM";
                    else                              result = "FAIL";
                }
                else
                {
                    result = "OFF-LINE";
                }
            }
            else if (sConfig.CommType == 1)
            {
                // UART
                if (sData.CommFail == false)
                {
                    result = "NORM";
                }
                else
                {
                    result = "FAIL";
                }
            }
            else
            {
                // CAN
                if (sData.CommFail == false)
                {
                    result = "NORM";
                }
                else
                {
                    result = "FAIL";
                }
            }

            return result;
        }

        private static string GetCommStatus(DeviceSystemTotalData tData)
        {
            string result = "";

            if (tData.CommFail)
                result = "OFF-LINE";
            else
                result = "NORM";

            return result;
        }

        private static byte[] WriteTotalData(DateTime aLog, CommConfig sConfig, DeviceSystemTotalData tData)
        {
            string tt;
            string sdata;

            tt = aLog.ToString("yyyy-MM-dd HH:mm:ss");
            sdata = String.Format(
                "{0};{1};{2};{3};{4};{5};{6};{7};{8};{9};"
                , tt                                                                                    //  0    DATETIME 
                , GetInterface(sConfig.CommType)                                                        //  1    INTERFACE
                , GetModelName(sConfig)                                                                 //  2    MODEL 
                , GetCommStatus(tData)                                                                  //  3    COMM STATUS 
                , GetStatusString(tData.StatusData.status)                                              //  4    STATUS 
                , GetAlarmString(tData.StatusData.batteryStatus)                                        //  5    ALARM
                , String.Format("{0:#0.0}", Convert.ToDouble(tData.ValueData.TotalVoltage) / 10)        //  6    voltageOfPack
                , String.Format("{0:#0.0}", Convert.ToDouble(tData.ValueData.TotalCurrent) / 10)        //  7    current
                , String.Format("{0:#0.0}", Convert.ToDouble(tData.ValueData.TotalSOC) / 10)            //  8    SOC
                , String.Format("{0:#0.0}", Convert.ToDouble(tData.ValueData.TotalTemp) / 10)           //  9    Max Temperature
                );
            sdata += "\r\n";

            Byte[] info =
                   new UTF8Encoding(true).GetBytes(sdata);

            return info;
        }

        private static byte[] WriteData(DateTime aLog, CommConfig sConfig, DeviceSystemData sData)
        {
            string tt;
            string sdata;

            tt = aLog.ToString("yyyy-MM-dd HH:mm:ss");
            sdata = String.Format(
                "{0};{1};{2};{3};{4};{5};{6};{7};{8};"
                , tt                                                                                    //  0    DATETIME 
                , GetInterface(sConfig.CommType)                                                        //  1    INTERFACE
                , GetModelName(sConfig)                                                                 //  2    MODEL 
                , GetCommStatus(sConfig, sData)                                                         //  3    COMM STATUS 
                , GetStatusString(sData.StatusData.status)                                              //  4    STATUS 
                , GetAlarmString(sData.StatusData.alarm)                                                //  5    ALARM
                , String.Format("{0:#0.0}", Convert.ToDouble(sData.ValueData.voltageOfPack) / 10)       //  6    voltageOfPack
                , String.Format("{0:#0.0}", Convert.ToDouble(sData.ValueData.current) / 10)             //  7    current
                , String.Format("{0:#0.0}", Convert.ToDouble(sData.ValueData.rSOC) / 10)                //  8    SOC
                );

            for (int i = 0; i < csConstData.SystemInfo.MAX_MODULE_CELL_SIZE; i++)
            {
                sdata += String.Format("{0:#0.000};", Convert.ToDouble(sData.ValueData.CellVoltage[i]) / 1000);                  // 27    Cell Voltage n
            }

            for (int i = 0; i < csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE; i++)
            {
                sdata += String.Format("{0:#0.0};", Convert.ToDouble(sData.ValueData.CellTemperature[i]) / 10);                  // 27    Cell Temperature n
            }

            sdata += String.Format("{0:#0.0};", Convert.ToDouble(sData.ValueData.CpuTemperature) / 10);                  // 27    Cell Temperature n

            sdata += String.Format(
                "{0};{1};{2};{3};"
                , String.Format("0x{0}", sData.StatusData.warning.ToString("X4"))                                       // 0    Warning
                , String.Format("0x{0}", sData.StatusData.protect.ToString("X4"))                                    // 1    Protection
                , String.Format("0x{0}", sData.StatusData.cellBallanceStatusLv.ToString("X4"))                            // 2    cellBallanceStatusLv
                , String.Format("0x{0}", sData.StatusData.cellBallanceStatusHv.ToString("X4"))                            // 3    cellBallanceStatusHv
                );
            sdata += "\r\n";

            Byte[] info =
                   new UTF8Encoding(true).GetBytes(sdata);

            return info;
        }
        #endregion

        #region DATA PRINT

        public static string data_print(byte[] data, int len)
        {
            byte[] ASC;
            int i, j;
            string result = "";

            ASC = new byte[20];

            if (len > 2)
            {
                if (ASC != null)
                {
                    for (i = 0; i < (len / 16 + 1); i++)
                    {
                        result += String.Format("0x{0:X8}  ", (int)(i * 16));
                        for (j = 0; j < 16; j++)
                        {
                            if ((i * 16 + j) >= data.Length)
                            {
                                result += "   ";
                                ASC[j] = (byte)' ';
                            }
                            else
                            {
                                result += String.Format("{0:X2} ", data[(i * 16) + j]);
                                if (data[i * 16 + j] < ' ')
                                    ASC[j] = (byte)'.';
                                else
                                {
                                    if ((j == 15) && (data[i * 16 + j] > 128))
                                        ASC[j] = (byte)'.';
                                    else
                                        ASC[j] = data[i * 16 + j];
                                }
                            }
                        }
                        ASC[16] = 0x00;
                        result += "\r\n";
                        //result += String.Format("  {0}\r\n", ASC.ToArray<byte>().ToString());
                    }
                }
                result += "\r\n";
                //result += String.Format("ID: {0:X2}\r\n", data[6]);
                //result += String.Format("CMD: {0:X2}\r\n", data[7]);
                //result += String.Format("S-A: {0:X4}({0:d})\r\n", (data[8] << 8) | data[9]);
                //result += String.Format("S-L: {0:X4}({0:d})\r\n", (data[10] << 8) | data[11]);
            }

            return result;
        }

        #endregion
    }
}
