using LFP_Manager.DataStructure;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace LFP_Manager.Utils
{
    class csDbProcess
    {
        // Query - SELECT * FROM TABLE_NAME like('%neon%',field_name) - 문자를 포함하는 데이터 검색
        public static string DbFileName = @"LFPS-48100S-J_INV.db";
        public static string DbFilePathFormat = @"\db\";
        public static string DbFileNameFormat = @"\db\{0}_{1}.db";
        public static string DbSchemaTableFileName = @"\sql\DB_SCHEMA_TABLE.sql";
        public static string ModuleTableName = @"TModule";

        public static string LogDbFilePath = @"\db";
        public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB";
        public static string LogDbSchemaTableFileName = @"\sql\LOG_DB_SCHEMA_TABLE.sql";

        public static DateTime Delay(int ms)
        {
            DateTime thisMoment = DateTime.Now;
            TimeSpan duration = new TimeSpan(0, 0, 0, 0, ms);
            DateTime afterMoment = thisMoment.Add(duration);

            while (afterMoment >= thisMoment)
            {
                System.Windows.Forms.Application.DoEvents();

                thisMoment = DateTime.Now;
            }

            return DateTime.Now;
        }

        //트랜잭션 시작
        public static void BeginTran(SQLiteConnection conn)
        {
            SQLiteCommand command = new SQLiteCommand("Begin", conn);
            command.ExecuteNonQuery();
            command.Dispose();
        }

        //트랜잭션 완료
        public static void CommitTran(SQLiteConnection conn)
        {
            SQLiteCommand command = new SQLiteCommand("Commit", conn);
            command.ExecuteNonQuery();
            command.Dispose();
        }

        #region CREATE DATABASE

        public static void DbCreate(string mSN, string bName)
        {
            string result = "";
            string dbFilename = String.Format(DbFileNameFormat, MakeLotNumber(mSN, bName), bName);
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
                Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilePath));

            if (File.Exists(dbFilePath) == true)
            {
                //throw new Exception("Already have db file - Failed to create db file");
                return;
            }
            else
            {
                // Create database
                SQLiteConnection.CreateFile(dbFilePath);
            }

            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Create table
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + DbSchemaTableFileName;
                        string query = File.ReadAllText(schemaFile);

                        command.CommandText = query;
                        SQLiteDataReader reader = null;
                        reader = command.ExecuteReader();
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return;
        }

        public static void LogDbCreate(string aModel)
        {
            string result = "";
            string ModelName = aModel;
            //public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB";
            string dbFilename = String.Format(LogDbFileNameFormat
                , String.Format("{0:yyMM}", DateTime.Now)
                , String.Format("{0:yyMMdd}", DateTime.Now)
                , ModelName
                );
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
                Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilePath));

            if (File.Exists(dbFilePath) == true)
            {
                //throw new Exception("Already have db file - Failed to create db file");
                return;
            }
            else
            {
                // Create database
                SQLiteConnection.CreateFile(dbFilePath);
            }

            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Create table
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + LogDbSchemaTableFileName;
                        string query = File.ReadAllText(schemaFile);

                        command.CommandText = query;
                        SQLiteDataReader reader = null;
                        reader = command.ExecuteReader();
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return;
        }

        public static void LogDbCreateNew(string aModel)
        {
            string result = "";
            string ModelName = aModel;
            //public static string LogDbFileNameFormat = @"\{0}\{1}_{2}_LOG.DB";
            string dbFilename = String.Format(LogDbFileNameFormat
                , String.Format("{0:yyMM}", DateTime.Now)
                , String.Format("{0:yyMMdd}", DateTime.Now)
                , ModelName
                );
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
                Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilePath));

            // Create database
            SQLiteConnection.CreateFile(dbFilePath);

            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Create table
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + LogDbSchemaTableFileName;
                        string query = File.ReadAllText(schemaFile);

                        command.CommandText = query;
                        SQLiteDataReader reader = null;
                        reader = command.ExecuteReader();
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return;
        }

        #endregion

        #region MAKE LOT NUMBER
        public static string MakeLotNumber(string mSN)
        {
            string LotNo = mSN.Substring(1, 11) + "000";
            return LotNo;
        }

        public static string MakeLotNumber(string mSN, string bName)
        {
            string LotNo;

            if (bName == "BMCB_J")
                LotNo = mSN.Substring(0, 10) + "0000";
            else
                LotNo = mSN.Substring(1, 11) + "000";
            return LotNo;
        }

        #endregion

        #region Excute Database
        public static DataTable DbSqlExcute(string path, string query, bool create_db_flag = false)
        {
            string result = "";
            DataTable dtResult = null;
            string dbFilename = Path.GetDirectoryName(path) + DbFileName;

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

            // Create database
            if (File.Exists(dbFilename) == false)
            {
                if (create_db_flag == true)
                    SQLiteConnection.CreateFile(dbFilename);
                else
                    throw new Exception("No database file - " + DbFileName);
            }

            // Open database
            string strConn = @"Data Source=" + dbFilename;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Create table
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //command.CommandText = "CREATE TABLE File (Name text, Size bigint, Modified datetime);";
                        command.CommandText = query;
                        SQLiteDataReader reader = null;
                        //command.ExecuteNonQuery();
                        reader = command.ExecuteReader();
                        dtResult = new DataTable();
                        dtResult.Load(reader);
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return dtResult;
        }

        public static DataTable DbSqlExcuteA1(string path, string query)
        {
            DataTable dtResult = null;
            string dbFilename = System.IO.Path.GetDirectoryName(path) + DbFileName;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilename)) == false)
                Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dbFilename));

            if (File.Exists(dbFilename) == false)
                // Create database
                SQLiteConnection.CreateFile(dbFilename);

            // Open database
            string strConn = @"Data Source=" + dbFilename;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Excute Query
                    var adpt = new SQLiteDataAdapter(query, connection);
                    DataSet ds = new DataSet();
                    adpt.Fill(ds);

                    dtResult = ds.Tables[0];
                }
                catch (Exception e)
                {
                    throw e;
                }
                finally
                {
                    connection.Close();
                }
            }
            return dtResult;
        }

        public static DataTable DbSqlExcuteA(string lot, string query, string bName, bool create_db_flag = false)
        {
            string result = "";
            DataTable dtResult = new DataTable();
            string lotNo = lot;
            string dbFilename = String.Format(DbFileNameFormat, lotNo, bName);
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename;

            if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false)
            {
                if (create_db_flag)
                    Directory.CreateDirectory(Path.GetDirectoryName(dbFilePath));
                else
                    throw new Exception("No DB file path - " + Path.GetDirectoryName(dbFilePath));
            }
            if (File.Exists(dbFilePath) == false)
            {
                if (create_db_flag)
                    SQLiteConnection.CreateFile(dbFilePath);
                else
                    throw new Exception(String.Format("No DB file - DbSqlExcuteA ({0})", dbFilename));
            }

            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Excute Query
                    var adpt = new SQLiteDataAdapter(query, connection);
                    DataSet ds = new DataSet();
                    adpt.Fill(ds);
                    if (ds.Tables.Count > 0)
                        dtResult = ds.Tables[0];
                }
                catch (Exception ex)
                {
                    result = ex.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return dtResult;
        }

        public static DataTable DbSqlExcuteA2(string dbFileName, string query, bool create_db_flag = false)
        {
            string result = "";
            DataTable dtResult = new DataTable();
            string lotNo = dbFileName.Substring(0, 9);
            string dbFilename = String.Format(DbFilePathFormat, lotNo) + dbFileName;
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename;

            if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false)
            {
                if (create_db_flag)
                    Directory.CreateDirectory(Path.GetDirectoryName(dbFilePath));
                else
                    throw new Exception("No DB file path - " + Path.GetDirectoryName(dbFilePath));
            }
            if (File.Exists(dbFilePath) == false)
            {
                if (create_db_flag)
                    SQLiteConnection.CreateFile(dbFilePath);
                else
                    throw new Exception(String.Format("No DB file - DbSqlExcuteA ({0})", dbFilename));
            }

            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Excute Query
                    var adpt = new SQLiteDataAdapter(query, connection);
                    DataSet ds = new DataSet();
                    adpt.Fill(ds);
                    if (ds.Tables.Count > 0)
                        dtResult = ds.Tables[0];
                }
                catch (Exception ex)
                {
                    result = ex.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return dtResult;
        }
        public static DataTable DbSqlExcuteA3(string dbFileName, string query, bool create_db_flag = false)
        {
            string result = "";
            DataTable dtResult = new DataTable();
            string dbFilePath = dbFileName;

            if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false)
            {
                if (create_db_flag)
                    Directory.CreateDirectory(Path.GetDirectoryName(dbFilePath));
                else
                    throw new Exception("No DB file path - " + Path.GetDirectoryName(dbFilePath));
            }
            if (File.Exists(dbFilePath) == false)
            {
                if (create_db_flag)
                    SQLiteConnection.CreateFile(dbFilePath);
                else
                    throw new Exception(String.Format("No DB file - DbSqlExcuteA ({0})", dbFileName));
            }

            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                connection.Open();
                try
                {
                    // Excute Query
                    var adpt = new SQLiteDataAdapter(query, connection);
                    DataSet ds = new DataSet();
                    adpt.Fill(ds);
                    if (ds.Tables.Count > 0)
                        dtResult = ds.Tables[0];
                }
                catch (Exception ex)
                {
                    result = ex.Message;
                }
                finally
                {
                    connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return dtResult;
        }

        #endregion

        #region BMS DATA INSERT AND UPDATE

        public static void BmsLogDataInsert(string modelName, ref DeviceSystemData systemData, DateTime dateTime, int cvUnit)
        {
            if (string.IsNullOrEmpty(modelName))
                throw new ArgumentNullException(nameof(modelName));
            if (systemData == null)
                throw new ArgumentNullException(nameof(systemData));
            if (cvUnit <= 0)
                throw new ArgumentException("cvUnit must be greater than 0", nameof(cvUnit));

            string dbFilename = GetLogDbFileName(modelName);
            string dbFilePath = GetLogDbFilePath(dbFilename);
            ValidateDbPath(dbFilePath);

            using (var connection = new SQLiteConnection(string.Format("Data Source={0}", dbFilePath)))
            {
                try
                {
                    connection.Open();
                    using (var transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            InsertModuleData(connection, modelName, systemData, dateTime, cvUnit);
                            transaction.Commit();
                        }
                        catch
                        {
                            transaction.Rollback();
                            throw;
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Failed to insert BMS log data: {0}", ex.Message), ex);
                }
            }
        }

        private static string GetLogDbFileName(string modelName)
        {
            return string.Format(LogDbFileNameFormat,
                DateTime.Now.ToString("yyMM"),
                DateTime.Now.ToString("yyMMdd"),
                modelName);
        }

        private static string GetLogDbFilePath(string dbFilename)
        {
            string exePath = Path.GetDirectoryName(Application.ExecutablePath);
            // LogDbFilePath가 이미 '\'로 시작한다면 제거
            string cleanLogPath = LogDbFilePath.TrimStart('\\');
            string cleanDbFilename = dbFilename.TrimStart('\\');
            string fullPath = Path.Combine(exePath, cleanLogPath);
            return Path.Combine(fullPath, cleanDbFilename);
        }

        private static void ValidateDbPath(string dbFilePath)
        {
            string directory = Path.GetDirectoryName(dbFilePath);
            if (!Directory.Exists(directory))
                throw new DirectoryNotFoundException(string.Format("Log DB directory not found: {0}", directory));
            if (!File.Exists(dbFilePath))
                throw new FileNotFoundException(string.Format("Log DB file not found: {0}", dbFilePath));
        }

        private static void InsertModuleData(SQLiteConnection connection, string modelName, DeviceSystemData systemData, DateTime dateTime, int cvUnit)
        {
            var columnNames = GetColumnNames(systemData);
            var parameters = CreateParameters(systemData, dateTime, cvUnit);

            using (var command = connection.CreateCommand())
            {
                var paramNames = new List<string>();
                foreach (var param in parameters)
                {
                    paramNames.Add("@" + param.ParameterName);
                }

                command.CommandText = string.Format(
                    "INSERT INTO TModuleValue ({0}) VALUES ({1})",
                    string.Join(", ", columnNames),
                    string.Join(", ", paramNames));

                command.Parameters.AddRange(parameters);
                command.ExecuteNonQuery();
            }
        }

        private static List<string> GetColumnNames(DeviceSystemData systemData)
        {
            var columns = new List<string>
            {
                "create_date",
                "module_no",
                "model_name",
                "module_sn",
                "fw_ver",
                "comm_fail",
                "op_status",
                "alarm_status",
                "warning",
                "fault",
                "module_voltage",
                "module_current",
                "module_soc",
                "module_soh",
                "module_cyclecount"
            };

            // Add cell voltage columns
            for (int i = 1; i <= systemData.cellQty; i++)
            {
                columns.Add(string.Format("cell_voltage_{0:00}", i));
            }

            // Add temperature columns
            for (int i = 1; i <= systemData.tempQty; i++)
            {
                columns.Add(string.Format("temperature_{0:00}", i));
            }

            columns.Add("ext1_temp");
            columns.Add("ext2_temp");
            columns.Add("chg_option");

            return columns;
        }

        private static SQLiteParameter[] CreateParameters(DeviceSystemData systemData, DateTime dateTime, int cvUnit)
        {
            var parameters = new List<SQLiteParameter>
            {
                new SQLiteParameter("create_date", dateTime),
                new SQLiteParameter("module_no", systemData.mNo),
                new SQLiteParameter("model_name", systemData.Information.ModelName),
                new SQLiteParameter("module_sn", systemData.Information.HwSerialNumber),
                new SQLiteParameter("fw_ver", systemData.Information.SwProductRev),
                new SQLiteParameter("comm_fail", systemData.ShelfCommFail),
                new SQLiteParameter("op_status", systemData.StatusData.status),
                new SQLiteParameter("alarm_status", systemData.StatusData.batteryStatus),
                new SQLiteParameter("warning", systemData.StatusData.warning),
                new SQLiteParameter("fault", systemData.StatusData.protection),
                new SQLiteParameter("module_voltage", (systemData.ValueData.voltageOfPack / 10.0).ToString()),
                new SQLiteParameter("module_current", (systemData.ValueData.current / 10.0).ToString()),
                new SQLiteParameter("module_soc", (systemData.ValueData.rSOC / 10.0).ToString()),
                new SQLiteParameter("module_soh", (systemData.ValueData.stateOfHealth / 10.0).ToString()),
                new SQLiteParameter("module_cyclecount", systemData.ValueData.cycleCount.ToString())
            };

            // Add cell voltage parameters
            for (int i = 0; i < systemData.cellQty; i++)
            {
                parameters.Add(new SQLiteParameter(
                    string.Format("cell_voltage_{0:00}", i + 1),
                    (systemData.ValueData.CellVoltage[i] / (float)cvUnit).ToString()));
            }

            // Add temperature parameters
            for (int i = 0; i < systemData.tempQty; i++)
            {
                parameters.Add(new SQLiteParameter(
                    string.Format("temperature_{0:00}", i + 1),
                    (systemData.ValueData.CellTemperature[i] / 10.0).ToString()));
            }

            parameters.Add(new SQLiteParameter("ext1_temp", (systemData.ValueData.Ext1Temperature / 10.0).ToString()));
            parameters.Add(new SQLiteParameter("ext2_temp", (systemData.ValueData.Ext2Temperature / 10.0).ToString()));
            parameters.Add(new SQLiteParameter("chg_option", systemData.CalibrationData.ChaMode.Mode.ToString()));

            return parameters.ToArray();
        }

        public static DataTable GetDataTable(string bSN, string aTableName, string bName)
        {
            string result = "";
            DataTable dtResult = null;
            string dbFilename = String.Format(DbFileNameFormat, MakeLotNumber(bSN, bName), bName);
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + dbFilename;

            if (Directory.Exists(Path.GetDirectoryName(dbFilePath)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFilePath) == false)
                throw new Exception("No DB file");
            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                Forms.fmxWait WaitForm = new Forms.fmxWait();
                WaitForm.StartPosition = FormStartPosition.CenterScreen;
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    WaitForm.Show();
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = String.Format("SELECT * FROM {0}", aTableName);
                        SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                        adapter.AcceptChangesDuringFill = false;
                        dtResult = new DataTable();
                        adapter.Fill(dtResult);
                        dtResult.TableName = aTableName;

                        CommitTran(connection);

                        System.Windows.Forms.Application.DoEvents();
                        WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1));
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (WaitForm != null)
                        WaitForm.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return dtResult;
        }

        public static DataTable GetDataTableBySelect(string bSN, string sql, string aTableName, string bName)
        {
            string result = "";
            DataTable dtResult = null;
            string dbFilename = String.Format(DbFileNameFormat, MakeLotNumber(bSN, bName), bName);
            string dbFilePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + dbFilename;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFilePath) == false)
                throw new Exception(String.Format("No DB file - {0}", dbFilePath));
            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                Forms.fmxWait WaitForm = new Forms.fmxWait();
                WaitForm.StartPosition = FormStartPosition.CenterScreen;
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    WaitForm.Show();
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = sql;
                        SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                        adapter.AcceptChangesDuringFill = false;
                        dtResult = new DataTable();
                        adapter.Fill(dtResult);
                        dtResult.TableName = aTableName;

                        System.Windows.Forms.Application.DoEvents();
                        WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1));

                        CommitTran(connection);
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (WaitForm != null)
                        WaitForm.Close();
                    if (result != "")
                        throw new Exception(result);
                }
            }
            return dtResult;
        }

        public static DataTable GetDataTableBySelectFromDbName(string dbFileName, string sql, string aTableName, string bName)
        {
            string result = "";
            DataTable dtResult = null;

            string lotNo = csDbUtils.MakeLotNumber(dbFileName.Substring(0, 8), bName);
            string dbFilename = String.Format(@"\db\{0}\{1}", lotNo, dbFileName);
            string dbFilePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + dbFilename;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFilePath) == false)
                throw new Exception(String.Format("No DB file - {0}", dbFilePath));
            // Open database
            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                Forms.fmxWait WaitForm = new Forms.fmxWait();
                WaitForm.StartPosition = FormStartPosition.CenterScreen;
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    WaitForm.Show();
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = sql;
                        SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                        adapter.AcceptChangesDuringFill = false;
                        dtResult = new DataTable();
                        adapter.Fill(dtResult);
                        dtResult.TableName = aTableName;

                        System.Windows.Forms.Application.DoEvents();
                        WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1));

                        CommitTran(connection);
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (WaitForm != null)
                        WaitForm.Close();
                    if (result != "")
                        throw new Exception(result);
                }
            }
            return dtResult;
        }

        public static DataTable GetDataTableByFileName(string fileName, string sql, string aTableName)
        {
            string result = "";
            DataTable dtResult = null;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(fileName)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(fileName) == false)
                throw new Exception("No DB file");
            // Open database
            string strConn = @"Data Source=" + fileName;
            using (var connection = new SQLiteConnection(strConn))
            {
                Forms.fmxWait WaitForm = new Forms.fmxWait();
                WaitForm.StartPosition = FormStartPosition.CenterScreen;
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    WaitForm.Show();
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = sql;
                        SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                        adapter.AcceptChangesDuringFill = false;
                        dtResult = new DataTable();
                        adapter.Fill(dtResult);
                        dtResult.TableName = aTableName;

                        System.Windows.Forms.Application.DoEvents();
                        WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1));

                        CommitTran(connection);
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (WaitForm != null)
                        WaitForm.Close();
                    if (result != "")
                        throw new Exception(result);
                }
            }
            return dtResult;
        }

        public static DataTable GetModuleMatchTableByFgNo(string fg_no, string bName)
        {
            DataTable dtResult = null;

            int a, b, c;
            a = Convert.ToInt32(fg_no);
            b = a / 300 + 1;
            c = a % 300;
            if ((c == 0) && (b > 0)) b--;
            string mSN = String.Format("1{0:yy}{1:00}{2:000}", DateTime.Now, b, c);
            string lotNo = csDbUtils.MakeLotNumber(mSN, bName);
            string dbfilePath = Path.GetDirectoryName(Application.ExecutablePath) + String.Format(DbFilePathFormat, lotNo);
            string[] filePaths = Directory.GetFiles(dbfilePath, "*.db");

            if (filePaths.Length > 0)
            {
                for (int i = 0; i < filePaths.Length; i++)
                {
                    string fileName = Path.GetFileName(filePaths[i]);
                    byte[] bfilName = Encoding.ASCII.GetBytes(fileName);

                    dtResult = GetDataTableByFileName(filePaths[i], String.Format("SELECT * FROM TModuleMatch where fg_no={0}", fg_no), "TModuleMatch");
                    if ((dtResult != null) && (dtResult.Rows.Count == 1)) break;
                }
            }
            if ((dtResult == null) || (dtResult.Rows.Count == 0))
                throw new Exception(String.Format("No match data - {0}", fg_no));

            return dtResult;
        }

        public static void BmsPcbMatchDataInsert(string dbFileName, DataRow sRow)
        {
            string result = "";
            int resultCode = (int)SQLiteErrorCode.Unknown;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFileName)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFileName) == false)
                throw new Exception(String.Format("No DB file - BmsDataInsert ({0})", dbFileName));

            // Open database
            string strConn = @"Data Source=" + dbFileName;
            using (var connection = new SQLiteConnection(strConn))
            {
                Forms.fmxWait WaitForm = new Forms.fmxWait
                {
                    StartPosition = FormStartPosition.CenterScreen
                };

                try
                {
                    connection.Open();
                    BeginTran(connection);

                    WaitForm.Show();
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = "INSERT INTO"
                            + " TBmsPcbMatchTable"
                            + " (PCB1_SERIAL_NUMBER, MODULE_SERIAL_NUMBER, create_date, modify_date)"                                                          // 2
                            + " Values (?,?,?,?);";
                        SQLiteParameter[] p = new SQLiteParameter[4];

                        for (int i = 0; i < 4; i++)
                        {
                            p[i] = new SQLiteParameter();
                            command.Parameters.Add(p[i]);
                        }

                        int j = 0;
                        p[j++].Value = sRow["PCB1_SERIAL_NUMBER"];                          // pcb_sn
                        p[j++].Value = sRow["MODULE_SERIAL_NUMBER"];                        // module_sn
                        p[j++].Value = DateTime.Now;                                        // create_date
                        p[j++].Value = DateTime.Now;                                        // modify_date

                        command.ExecuteNonQuery();

                        WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1));
                        System.Windows.Forms.Application.DoEvents();

                        CommitTran(connection);
                    }
                }
                catch (SQLiteException sqle)
                {
                    // Handle DB exception
                    result = sqle.Message;
                    resultCode = sqle.ErrorCode;
                }
                catch (IndexOutOfRangeException ie)
                {
                    // If you think there might be a problem with index range in the loop, for example
                    result = ie.Message;
                    resultCode = 9999;
                }
                catch (Exception ex)
                {
                    result = ex.Message;
                    resultCode = 9998;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (WaitForm != null)
                        WaitForm.Close();
                    if (result != "")
                    {
                        if (resultCode == 9998) throw new Exception(result);
                        else if (resultCode == 9999) throw new IndexOutOfRangeException(result);
                        else throw new SQLiteException((SQLiteErrorCode)resultCode, result);
                    }
                }
            }
        }

        public static void ErrorLogInsert(string dbFileName, DataRow sRow, string Process, string ErrType, string ErrMsg)
        {
            string result = "";

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFileName)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFileName) == false)
                throw new Exception(String.Format("No DB file - ErrorLogInsert ({0})", dbFileName));

            // Open database
            string strConn = @"Data Source=" + dbFileName;
            using (var connection = new SQLiteConnection(strConn))
            {
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = "INSERT INTO"
                            + " TErrorLogTable"
                            + " (create_date, MODULE_SERIAL_NUMBER, PCB1_SERIAL_NUMBER, PROCESS, ERROR_TYPE, ERROR_MSG)"                                                          // 2
                            + " Values (?,?,?,?,?,?);";
                        SQLiteParameter[] p = new SQLiteParameter[6];

                        for (int i = 0; i < 6; i++)
                        {
                            p[i] = new SQLiteParameter();
                            command.Parameters.Add(p[i]);
                        }

                        int j = 0;
                        p[j++].Value = DateTime.Now;                                        // create_date
                        p[j++].Value = sRow["MODULE_SERIAL_NUMBER"];                        // module_sn
                        p[j++].Value = sRow["PCB1_SERIAL_NUMBER"];                          // pcb_sn
                        p[j++].Value = Process;                                             // process
                        p[j++].Value = ErrType;                                             // error type
                        p[j++].Value = ErrMsg;                                              // error message

                        command.ExecuteNonQuery();

                        CommitTran(connection);
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
        }

        #endregion

        #region SELECT QUARY

        public static int DbQuaryExcuteToDataTable(string dbFileName, string Quary, ref DataTable rDT)
        {
            int result = 0;
            string resultStr = String.Empty;

            string strConn = @"Data Source=" + dbFileName;
            using (var connection = new SQLiteConnection(strConn))
            {
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = Quary;
                        SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                        adapter.AcceptChangesDuringFill = false;
                        rDT = new DataTable();
                        adapter.Fill(rDT);
                        //rDT.TableName = "TModuleValue";

                        CommitTran(connection);

                        result = rDT.Rows.Count;

                        System.Windows.Forms.Application.DoEvents();
                    }
                }
                catch (Exception e)
                {
                    resultStr = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (resultStr != "") throw new Exception(resultStr);
                }
            }
            return result;
        }

        public static void CreateLogDbFile(string dbFileName)
        {
            string result = "";

            if (Directory.Exists(Path.GetDirectoryName(dbFileName)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFileName) == true)
                throw new Exception(String.Format("Already have DB file - DbQuaryExcuteToDbFile({0})", dbFileName));

            // Create database
            SQLiteConnection.CreateFile(dbFileName);

            // Open database
            string strConn = @"Data Source=" + dbFileName;
            using (var connection = new SQLiteConnection(strConn))
            {
                Forms.fmxWait WaitForm = new Forms.fmxWait();
                WaitForm.StartPosition = FormStartPosition.CenterScreen;
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    WaitForm.Show();
                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        string schemaFile = Path.GetDirectoryName(Application.ExecutablePath) + LogDbSchemaTableFileName;
                        string query = File.ReadAllText(schemaFile);

                        command.CommandText = query;
                        SQLiteDataReader reader = null;
                        reader = command.ExecuteReader();

                        WaitForm.SetDescription(String.Format("{0}//{1}", 1, 1));
                        System.Windows.Forms.Application.DoEvents();

                        CommitTran(connection);
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (WaitForm != null)
                        WaitForm.Close();
                    if (result != "") throw new Exception(result);
                }
            }
        }

        public static void DbInsertDataToDbFile(string dbFileName, DataRow dtRow)
        {
            string result = "";

            if (Directory.Exists(Path.GetDirectoryName(dbFileName)) == false)
                throw new Exception("No DB file path");
            if (File.Exists(dbFileName) == false)
                throw new Exception(String.Format("No DB file - DbInsertDataToDbFile({0})", dbFileName));

            // Open database
            string strConn = @"Data Source=" + dbFileName;
            using (var connection = new SQLiteConnection(strConn))
            {
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        command.CommandText = String.Format("INSERT INTO TModuleValue (");
                        command.CommandText += "create_date"                                // 0
                            + ", module_no"                                                 // 1
                            + ", pcb_sn"                                                    // 2
                            + ", module_sn"                                                 // 3
                            + ", fw_ver"                                                    // 4
                            + ", comm_fail"                                                 // 5
                            + ", op_status"                                                 // 6
                            + ", alarm_status"                                              // 7
                            + ", warning"                                                   // 8
                            + ", fault"                                                     // 9
                            + ", module_voltage"                                            // 10
                            + ", module_current"                                            // 11
                            + ", module_soc"                                                // 12
                            + ", module_soh"                                                // 13
                            ;
                        for (int i = 0; i < 15; i++)
                        {
                            command.CommandText += String.Format(", cell_voltage_{0:00}", i + 1);       // 14 ~ 28; 15 cells
                        }
                        for (int i = 0; i < 6; i++)
                        {
                            command.CommandText += String.Format(", temperature_{0:00}", i + 1);        // 29 ~ 34; 6 temps
                        }
                        command.CommandText += ""
                            + ", chg_option"                                                // 35
                            + ", chg_cal"                                                   // 36
                            + ", dch_cal"                                                   // 37
                            + ")"
                            + " Values (";

                        int total = dtRow.Table.Columns.Count;

                        for (int i = 0; i < (total - 1); i++) command.CommandText += "?,";
                        command.CommandText += "?);";

                        SQLiteParameter[] p = new SQLiteParameter[total];

                        for (int i = 0; i < total; i++)
                        {
                            if (i == 0)
                                p[i] = new SQLiteParameter(DbType.DateTime);
                            else
                                p[i] = new SQLiteParameter();
                            command.Parameters.Add(p[i]);
                        }

                        int j = 0;
                        p[j++].Value = String.Format("{0:yyyy/MM/dd HH:mm:ss}", dtRow["create_date"]);          //  0 create_date
                        p[j++].Value = dtRow["module_no"];                                                      //  1 module_no
                        p[j++].Value = dtRow["pcb_sn"];                                                         //  2 pcb_sn
                        p[j++].Value = dtRow["module_sn"];                                                      //  3 module_sn
                        p[j++].Value = dtRow["fw_ver"];                                                         //  4 fw_ver
                        p[j++].Value = dtRow["comm_fail"];                                                      //  5 comm_fail
                        p[j++].Value = dtRow["op_status"];                                                      //  6 op_status
                        p[j++].Value = dtRow["alarm_status"];                                                   //  7 alarm_status
                        p[j++].Value = dtRow["warning"];                                                        //  8 warning
                        p[j++].Value = dtRow["fault"];                                                          //  9 fault
                        p[j++].Value = dtRow["module_voltage"];                                                 // 10 module_voltage
                        p[j++].Value = dtRow["module_current"];                                                 // 11 module_current
                        p[j++].Value = dtRow["module_soc"];                                                     // 12 module_soc
                        p[j++].Value = dtRow["module_soh"];                                                     // 13 module_soh

                        for (int i = 0; i < 15; i++)
                        {
                            p[j++].Value = dtRow[String.Format("cell_voltage_{0:00}", i + 1)];                // 14 cell_voltage_01 28
                        }
                        for (int i = 0; i < 6; i++)
                        {
                            p[j++].Value = dtRow[String.Format("temperature_{0:00}", i + 1)];                 // 29 cell_voltage_01 36
                        }

                        p[j++].Value = dtRow["chg_option"];                                                     // 37 chg_option
                        p[j++].Value = dtRow["chg_cal"];                                                        // 38 chg_cal
                        p[j++].Value = dtRow["dch_cal"];                                                        // 39 dch_cal

                        command.ExecuteNonQuery();

                        CommitTran(connection);
                    }
                }
                catch (SQLiteException se)
                {
                    if (se.ResultCode != SQLiteErrorCode.Constraint)
                        result = se.Message;
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
        }

        public static DataTable BmsDataSelectToDataTable(CommConfig aConfig, DateTime aDate, string qry)
        {
            string result = "";
            DataTable dtResult = null;
            string ModelName = csConstData.MODEL_STR[aConfig.UartModelIndex];
            string dbFilename = String.Format(LogDbFileNameFormat
                , String.Format("{0:yyMM}", aDate)
                , String.Format("{0:yyMMdd}", aDate)
                , ModelName
                );
            string dbFilePath = Path.GetDirectoryName(Application.ExecutablePath) + LogDbFilePath + dbFilename;

            if (Directory.Exists(System.IO.Path.GetDirectoryName(dbFilePath)) == false)
                return dtResult;
            if (File.Exists(dbFilePath) == false)
                return dtResult;

            string strConn = @"Data Source=" + dbFilePath;
            using (var connection = new SQLiteConnection(strConn))
            {
                try
                {
                    connection.Open();
                    BeginTran(connection);

                    // Insert data
                    using (SQLiteCommand command = connection.CreateCommand())
                    {
                        //sSQL = "insert into TrendTable ( TrendStamp, TagName, TagValue) Values ( " + IntToStr(stamp) + "," + name + "," + value + ");";
                        command.CommandText = String.Format("SELECT * FROM TModuleValue {0}", qry);
                        SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                        adapter.AcceptChangesDuringFill = false;
                        dtResult = new DataTable();
                        adapter.Fill(dtResult);
                        dtResult.TableName = "TModuleValue";

                        CommitTran(connection);

                        System.Windows.Forms.Application.DoEvents();
                    }
                }
                catch (Exception e)
                {
                    result = e.Message;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                    if (result != "") throw new Exception(result);
                }
            }
            return dtResult;
        }
        #endregion

        public class SQLITE
        {
            private SQLiteConnection con;
            private SQLiteCommand cmd;
            private SQLiteDataAdapter adapter;

            public SQLITE(string databasename)
            {
                con = new SQLiteConnection(string.Format("Data Source={0};Compress=True;", databasename));
            }

            public int Execute(string sql_statement)
            {
                con.Open();
                cmd = con.CreateCommand();
                cmd.CommandText = sql_statement;
                int row_updated;
                try
                {
                    row_updated = cmd.ExecuteNonQuery();
                }
                catch
                {
                    con.Close();
                    return 0;
                }
                con.Close();
                return row_updated;
            }
            public DataTable GetDataTable(string tablename)
            {
                DataTable DT = new DataTable();
                con.Open();
                cmd = con.CreateCommand();
                cmd.CommandText = string.Format("SELECT * FROM {0}", tablename);
                adapter = new SQLiteDataAdapter(cmd);
                adapter.AcceptChangesDuringFill = false;
                adapter.Fill(DT);
                con.Close();
                DT.TableName = tablename;
                return DT;
            }
            public void SaveDataTable(DataTable DT)
            {
                try
                {
                    Execute(string.Format("DELETE FROM {0}", DT.TableName));
                    con.Open();
                    cmd = con.CreateCommand();
                    cmd.CommandText = string.Format("SELECT * FROM {0}", DT.TableName);
                    adapter = new SQLiteDataAdapter(cmd);
                    SQLiteCommandBuilder builder = new SQLiteCommandBuilder(adapter);
                    adapter.Update(DT);
                    con.Close();
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(Ex.Message);
                }
            }
        }
    }
}
