using LFP_Manager.DataStructure;
using LFP_Manager.Function;
using LFP_Manager.Utils;
using System;
using System.Data;
using System.Data.SQLite;
using System.Threading;
using System.Windows.Forms;

namespace LFP_Manager.Threads
{
    public delegate void DbDataPrint(object sender, string msg);

    class csDbThread
    {
        #region VARIABLES

        private CommConfig Config = new CommConfig();
        private DeviceSystemData[] SystemData;
        private short[] Status, oldStatus;

        private Thread dbProc = null;

        private bool Active = false;

        private int mQty = 1;

        private int ModuleID = 1;

        ////////////////////////////////////////
        private bool DbThreadEnd = true;

        public event DbDataPrint OnPrint = null;

        #endregion

        #region CONSTRUCTORS

        public csDbThread(int mID, CommConfig aConfig, DeviceSystemData[] aSystemData)
        {
            ModuleID = mID;
            Status = new short[2];
            oldStatus = new short[2]; 
            Config = aConfig;
            SystemData = aSystemData;

            dbProc = new Thread(dbThreadProcess);
        }

        public void disposeThread()
        {
            DbThreadEnd = true;
            if (dbProc != null)
            {
                if (dbProc.IsAlive)
                {
                    dbProc.Abort();
                }
                dbProc = null;
            }
        }

        public unsafe bool Start(int mID, CommConfig aConfig)
        {
            bool result = false;

            ModuleID = mID;
            Config = aConfig;
            switch (Config.CommType)
            {
                case csConstData.CommType.COMM_UART:                 // RS-232
                    mQty = 1;
                    break;
                case csConstData.CommType.COMM_RS485:                // RS-485
                    mQty = Config.ModuleQty;
                    break;
                case csConstData.CommType.COMM_SNMP:                 // SNMP
                    mQty = 1;
                    break;
                default:
                    mQty = 1;
                    break;
            }

            // DB Create with Path Create
            csHistoryFunction.DbCreate(System.IO.Path.GetDirectoryName(Application.ExecutablePath));

            try
            {
                DbThreadEnd = false;
                dbProc.Start();

                Active = true;
            }
            catch (Exception ex)
            {
                OnPrint?.Invoke(this, ex.Message);
            }

            return result;
        }

        public void Stop()
        {
            DbThreadEnd = true;

            Active = false;
        }

        public void UpdateStatus(short st1, short st2)
        {
            Status[0] = st1;
            Status[1] = st2;
        }

        #endregion

        #region UPDATE DATA

        public void UpdateData(int mID, DeviceSystemData[] aSystemData)
        {
            ModuleID = mID;
            SystemData = aSystemData;
        }

        #endregion

        #region MAKE ALARM HISTORY

        private void CheckAlarm()
        {
            bool[] Data1 = csUtils.Int16ToBitArray((short)Status[0]);
            bool[] Data2 = csUtils.Int16ToBitArray((short)Status[1]);
            bool[] oData1 = csUtils.Int16ToBitArray((short)oldStatus[0]);
            bool[] oData2 = csUtils.Int16ToBitArray((short)oldStatus[1]);

            // Cell Over Voltage
            if (oData2[0] != Data2[0])
            {
                if (Data2[0] == true)
                {
                    IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_TRIP);
                }
                else
                {
                    if (oData1[0] != Data1[0])
                    {
                        if (Data1[0] == true)
                            IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_WARNING);
                        else
                            IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_RELEASE);
                    }
                    else
                    {
                        if (Data1[0] == false)
                            IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_RELEASE);
                    }
                }
            }
            else
            {
                if (oData1[0] != Data1[0])
                {
                    if (Data1[0] == true)
                        IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_WARNING);
                    else
                        IDInsert("", csDbConstData.DB_ALARM.CELL_UNDER_VOLTAGE, csDbConstData.DB_ALARM.FLAG_RELEASE);
                }
            }
            oldStatus = Status;
        }

        #endregion

        #region DB INSERT DATA
        private void IDInsert(string mPath, int aCode, int fCode)
        {
            //string dbFilename = mPath + csDbConstData.DataBase.FileName;
            string dbFilename = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + csDbConstData.DataBase.FileName;

            // Open database
            string strConn = @"Data Source=" + dbFilename;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        command.CommandText = "BEGIN;"; //명시적 트렌젝션 시작
                        command.ExecuteNonQuery();

                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = "INSERT INTO " + csDbConstData.DataBase.TableName + "(HTime, model, sno, alarm_name, alarm_code, flag_name, flag, param1, param2) "
                                                        + " Values (@HTime, @model, @sno, @alarm_name, @alarm_code, @flag_name, @flag, @param1, @param2);";
                        SQLiteParameter[] p = new SQLiteParameter[]
                        {
                            new SQLiteParameter("@HTime", DbType.DateTime),
                            new SQLiteParameter("@model", DbType.String),
                            new SQLiteParameter("@sno", DbType.Int16),
                            new SQLiteParameter("@alarm_name", DbType.String),
                            new SQLiteParameter("@alarm_code", DbType.Int16),
                            new SQLiteParameter("@flag_name", DbType.String),
                            new SQLiteParameter("@flag", DbType.Int16),
                            new SQLiteParameter("@param1", DbType.Decimal),
                            new SQLiteParameter("@param2", DbType.Decimal),
                        }; // end SQLiteParameter

                        command.Parameters.AddRange(p);

                        int result = 0;

                        p[0].Value = DateTime.Now;              // DateTime
                        p[1].Value = "AAA";                     // Model Name
                        p[2].Value = 1;                         // System No
                        p[3].Value = csDbConstData.DB_ALARM.ALARM_NAME[aCode];       // alarm_name
                        p[4].Value = aCode;                     // alarm_code
                        p[5].Value = csDbConstData.DB_ALARM.FLAG_NAME[fCode];       // flag_name
                        p[6].Value = fCode;                     // flag_code
                        p[7].Value = 0.0;                       // param1
                        p[8].Value = 0.0;                       // param2

                        try
                        {
                            result = command.ExecuteNonQuery();
                        }
                        catch (Exception)
                        {
                        }
                        command.CommandText = "COMMIT;"; //명시적 트렌젝션 시작
                    }
                }
                catch (Exception)
                {
                    //MessageBox.Show(e.ToString());
                }
                finally
                {
                    connection.Close();
                }
            }
        }

        #endregion

        #region DB THREAD

        unsafe private void dbThreadProcess()
        {
            DateTime bakDateTime = DateTime.Now;
            int ss = Config.DbLogPeriod;

            while (DbThreadEnd == false)
            {
                if (Active)
                {
                    DateTime cDate = DateTime.Now;

                    if (
                        ((bakDateTime.Minute != cDate.Minute)
                        || (bakDateTime.Second != cDate.Second))
                        && ((cDate.Second % ss) == 0)
                        )
                    {
                        // Database Log Process
                        try
                        {
                            string ModelName;

                            ModelName = csConstData.MODEL_STR[Config.UartModelIndex];
                            csDbUtils.LogDbCreate(ModelName);

                            switch (Config.CommType)
                            {
                                case csConstData.CommType.COMM_UART:
                                    SystemData[ModuleID - 1].mNo = ModuleID;
                                    csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[ModuleID - 1], cDate, 1000);
                                    break;
                                case csConstData.CommType.COMM_RS485:
                                    if (mQty > 1)
                                    {
                                        for (int i = 0; i < mQty; i++)
                                        {
                                            SystemData[i].mNo = i + 1;
                                            csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[i], cDate, 1000);
                                        }
                                    }
                                    else
                                    {
                                        SystemData[ModuleID - 1].mNo = ModuleID;
                                        csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[ModuleID - 1], cDate, 1000);
                                    }
                                    break;
                                case csConstData.CommType.COMM_SNMP:
                                    SystemData[ModuleID - 1].mNo = ModuleID;
                                    csDbProcess.BmsLogDataInsert(ModelName, ref SystemData[ModuleID - 1], cDate, 1000);
                                    break;
                                default:
                                    break;
                            }
                        }
                        catch (Exception)
                        {
                        }
                        bakDateTime = cDate;
                    }
                }
                Thread.Sleep(100);
            }
        }

        #endregion
    }
}
