using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Security.Cryptography;
using System.Data;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Globalization;
using System.Threading;
using System.Diagnostics;
using System.Net;

using SystemX.Net.BaseProtocol;
using System.Xml.Linq;
using static SystemX.Net.Platform.Common.Util.LogMessage;
using System.Data.SqlClient;

namespace SystemX.Net.Middleware.Log.Commons
{
    using ParamElement = Tuple<SqlDbType, int, byte, byte>;

    public class HISTTesterSummary
    {
        public string StationName { set; get; }
        public string TestType { set; get; }
        public string Version { set; get; }
        public string ProdCode { set; get; }
        public int TestListFileNo { set; get; }
        public int TestListVariantNo { set; get; }
        public string TestListCntID { set; get; }

        public int StepVersion { set; get; }
        public string Host { set; get; }
        public string Section { set; get; }
        public string ProdNoC { set; get; }
        public string ProdNoP { set; get; }
        public string TestCode { set; get; }
        public string TestListFileName { set; get; }
        public string ProductID { set; get; }
        public string Result { set; get; }
        public string Duration { set; get; }
        public DateTime TestDT { set; get; }
    }

    public class HISTLogSummary
    {
        public string StationName { set; get; }
        public string TestType { set; get; }
        public string Version { set; get; }
        public string ProdCode { set; get; }
        public int TestListFileNo { set; get; }
        public int TestListVariantNo { set; get; }
        public string TestListCntID { set; get; }

        public int StepVersion { set; get; }
        public string Host { set; get; }
        public string Section { set; get; }
        public string ProdNoC { set; get; }
        public string ProdNoP { set; get; }
        public string TestCode { set; get; }
        public string TestListFileName { set; get; }
        public string ProductID { set; get; }
        public string Result { set; get; }
        public string Duration { set; get; }
        public DateTime TestDT { set; get; }
    }

    public static class ShortLogParamInfo
    {
        public static readonly int MessageLength = 4096;
        public static readonly int MessageValLength = 2024;

        public static string STEP = "";
        public static string POSITION = "";
        public static string MO = "";
        public static string FNC_NAME = "";
        public static string MIN = "";
        public static string MEASURE = "";
        public static string MAX = "";
        public static string DIM = "";
        public static string CHECK = "";
        public static string SPENT_TIME = "";
        public static string INFO = "";

        public static bool GLOBAL_SPEC = false;
        public static string VRFY_MIN = "";
        public static string VRFY_MAX = "";
    }

    public static class LongLogParamInfo
    {
        public static readonly int MessageLength = 4096;
        public static readonly int MessageValLength = 2024;

        public static string STEP = "";
        public static string POSITION = "";
        public static string MO = "";
        public static string FNC_NAME = "";
        public static string MIN = "";
        public static string MEASURE = "";
        public static string MAX = "";
        public static string DIM = "";
        public static string CHECK = "";
        public static string SPENT_TIME = "";
        public static string INFO = "";

        public static bool GLOBAL_SPEC = false;
        public static string VRFY_MIN = "";
        public static string VRFY_MAX = "";
    }

    public static class ParamSet
    {
        public static Dictionary<string, ParamElement> fParam = new Dictionary<string, ParamElement>();

        public static void TestResultField()
        {
            fParam.Clear();
            fParam = new Dictionary<string, ParamElement>();
            fParam.Add("No", new ParamElement(SqlDbType.BigInt, 0, 0, 0));
            fParam.Add("TestDT", new ParamElement(SqlDbType.DateTime2, 7, 0, 0));
            fParam.Add("LogData", new ParamElement(SqlDbType.NVarChar, -1, 0, 0));
        }

        public static void TesterSummaryField()
        {
            fParam.Clear();
            fParam = new Dictionary<string, ParamElement>();
            fParam.Add("StationName", new ParamElement(SqlDbType.NVarChar, 128, 0, 0));
            fParam.Add("TestType", new ParamElement(SqlDbType.NVarChar, 8, 0, 0));
            fParam.Add("Version", new ParamElement(SqlDbType.NVarChar, 4, 0, 0));
            fParam.Add("ProdCode", new ParamElement(SqlDbType.NVarChar, 4, 0, 0));
            fParam.Add("TestListFileNo", new ParamElement(SqlDbType.Int, 0, 0, 0));
            fParam.Add("TestListVariantNo", new ParamElement(SqlDbType.Int, 0, 0, 0));
            fParam.Add("TestListCntID", new ParamElement(SqlDbType.NVarChar, 256, 0, 0));
            fParam.Add("StepVersion", new ParamElement(SqlDbType.Int, 0, 0, 0));
            fParam.Add("HostID", new ParamElement(SqlDbType.NVarChar, 64, 0, 0));
            fParam.Add("Section", new ParamElement(SqlDbType.NVarChar, 64, 0, 0));
            fParam.Add("ProdNo_C", new ParamElement(SqlDbType.NVarChar, 32, 0, 0));
            fParam.Add("ProdNo_P", new ParamElement(SqlDbType.NVarChar, 32, 0, 0));
            fParam.Add("Testcode", new ParamElement(SqlDbType.NVarChar, 16, 0, 0));
            fParam.Add("TestListFileName", new ParamElement(SqlDbType.NVarChar, 256, 0, 0));
            fParam.Add("ProductID", new ParamElement(SqlDbType.NVarChar, 64, 0, 0));
            fParam.Add("Result", new ParamElement(SqlDbType.NVarChar, 16, 0, 0));
            fParam.Add("Duration", new ParamElement(SqlDbType.NVarChar, 16, 0, 0));
            fParam.Add("TestDT", new ParamElement(SqlDbType.DateTime2, 7, 0, 0));
        }

        public static void LogSummaryField()
        {
            fParam.Clear();
            fParam = new Dictionary<string, ParamElement>();
            fParam.Add("StationName", new ParamElement(SqlDbType.NVarChar, 128, 0, 0));
            fParam.Add("TestType", new ParamElement(SqlDbType.NVarChar, 8, 0, 0));
            fParam.Add("Version", new ParamElement(SqlDbType.NVarChar, 4, 0, 0));
            fParam.Add("ProdCode", new ParamElement(SqlDbType.NVarChar, 4, 0, 0));
            fParam.Add("TestListFileNo", new ParamElement(SqlDbType.Int, 0, 0, 0));
            fParam.Add("TestListVariantNo", new ParamElement(SqlDbType.Int, 0, 0, 0));
            fParam.Add("TestListCntID", new ParamElement(SqlDbType.NVarChar, 256, 0, 0));
            fParam.Add("StepVersion", new ParamElement(SqlDbType.Int, 0, 0, 0));
            fParam.Add("HostID", new ParamElement(SqlDbType.NVarChar, 64, 0, 0));
            fParam.Add("Section", new ParamElement(SqlDbType.NVarChar, 64, 0, 0));
            fParam.Add("ProdNo_C", new ParamElement(SqlDbType.NVarChar, 32, 0, 0));
            fParam.Add("ProdNo_P", new ParamElement(SqlDbType.NVarChar, 32, 0, 0));
            fParam.Add("Testcode", new ParamElement(SqlDbType.NVarChar, 16, 0, 0));
            fParam.Add("TestListFileName", new ParamElement(SqlDbType.NVarChar, 256, 0, 0));
            fParam.Add("ProductID", new ParamElement(SqlDbType.NVarChar, 64, 0, 0));
            fParam.Add("Result", new ParamElement(SqlDbType.NVarChar, 16, 0, 0));
            fParam.Add("Duration", new ParamElement(SqlDbType.NVarChar, 16, 0, 0));
            fParam.Add("TestDT", new ParamElement(SqlDbType.DateTime2, 7, 0, 0));
        }

        public static SqlParameter GetMakeSqlParameterInfo(Dictionary<string, ParamElement> refField, string strSetName, object objValue)
        {
            if (refField.ContainsKey(strSetName))
            {
                SqlParameter param = null;

                if (refField[strSetName].Item2 != 0)
                    param = new SqlParameter("@" + strSetName, refField[strSetName].Item1, refField[strSetName].Item2);
                else
                    param = new SqlParameter("@" + strSetName, refField[strSetName].Item1);

                if (refField[strSetName].Item1 == SqlDbType.Decimal)
                {
                    param.Precision = refField[strSetName].Item3;
                    param.Scale = refField[strSetName].Item4;
                }

                param.Value = objValue;
                return param;
            }
            else
                return null;
        }
    }

    public class CommonProtocol
    {
        public SqlCommand LogDataResultInsert(string strTableName, DataRow itemData)
        {
            string columns = string.Empty;
            columns = "No,TestDT,LogData";

            string values = string.Join(",", columns.Split(',').Select(c => string.Format("@{0}", c)));
            string sqlCommand = string.Format("INSERT INTO [" + strTableName + "] ({0}) VALUES ({1})", columns, values);

            ParamSet.TestResultField();

            SqlCommand cmd = new SqlCommand(sqlCommand);

            SqlParameter[] setParams = new SqlParameter[columns.Split(',').Count()];

            setParams[0] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "No", Convert.ToInt64(itemData["No"]));
            setParams[1] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestDT", Convert.ToDateTime(itemData["TestDT"]));
            setParams[2] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "LogData", Convert.ToString(itemData["LogData"]));

            cmd.Parameters.AddRange(setParams);

            return cmd;
        }

        public SqlCommand LogDataSummaryInsert(string strTableName, HISTLogSummary itemSummary)
        {
            string columns = string.Empty;
            if (itemSummary.TestListCntID == string.Empty)
                columns = "StationName,TestType,Version,ProdCode,TestListFileNo,TestListVariantNo,StepVersion,HostID,Section,ProdNo_C,ProdNo_P,Testcode,TestListFileName,ProductID,Result,Duration,TestDT";
            else
                columns = "StationName,TestType,Version,ProdCode,TestListFileNo,TestListVariantNo,TestListCntID,StepVersion,HostID,Section,ProdNo_C,ProdNo_P,Testcode,TestListFileName,ProductID,Result,Duration,TestDT";

            string values = string.Join(",", columns.Split(',').Select(c => string.Format("@{0}", c)));
            string sqlCommand = string.Format("INSERT INTO [" + strTableName + "] ({0}) VALUES ({1})", columns, values);

            ParamSet.LogSummaryField();

            SqlCommand cmd = new SqlCommand(sqlCommand);

            SqlParameter[] setParams = new SqlParameter[columns.Split(',').Count()];

            if (itemSummary.TestListCntID == string.Empty)
            {
                setParams[0] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "StationName", itemSummary.StationName);
                setParams[1] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestType", itemSummary.TestType);
                setParams[2] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Version", itemSummary.Version);
                setParams[3] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProdCode", itemSummary.ProdCode);
                setParams[4] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListFileNo", itemSummary.TestListFileNo);
                setParams[5] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListVariantNo", itemSummary.TestListVariantNo);
                setParams[6] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "StepVersion", itemSummary.StepVersion);
                setParams[7] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "HostID", itemSummary.Host);
                setParams[8] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Section", itemSummary.Section);
                setParams[9] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProdNo_C", itemSummary.ProdNoC);
                setParams[10] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProdNo_P", itemSummary.ProdNoP);
                setParams[11] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Testcode", itemSummary.TestCode);
                setParams[12] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListFileName", itemSummary.TestListFileName);
                setParams[13] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProductID", itemSummary.ProductID);
                setParams[14] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Result", itemSummary.Result);
                setParams[15] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Duration", itemSummary.Duration);
                setParams[16] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestDT", itemSummary.TestDT);
            }
            else
            {
                setParams[0] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "StationName", itemSummary.StationName);
                setParams[1] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestType", itemSummary.TestType);
                setParams[2] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Version", itemSummary.Version);
                setParams[3] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProdCode", itemSummary.ProdCode);
                setParams[4] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListFileNo", itemSummary.TestListFileNo);
                setParams[5] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListVariantNo", itemSummary.TestListVariantNo);
                setParams[6] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListCntID", itemSummary.TestListCntID);
                setParams[7] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "StepVersion", itemSummary.StepVersion);
                setParams[8] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "HostID", itemSummary.Host);
                setParams[9] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Section", itemSummary.Section);
                setParams[10] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProdNo_C", itemSummary.ProdNoC);
                setParams[11] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProdNo_P", itemSummary.ProdNoP);
                setParams[12] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Testcode", itemSummary.TestCode);
                setParams[13] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestListFileName", itemSummary.TestListFileName);
                setParams[14] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "ProductID", itemSummary.ProductID);
                setParams[15] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Result", itemSummary.Result);
                setParams[16] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "Duration", itemSummary.Duration);
                setParams[17] = ParamSet.GetMakeSqlParameterInfo(ParamSet.fParam, "TestDT", itemSummary.TestDT);
            }

            cmd.Parameters.AddRange(setParams);

            return cmd;
        }
    }

    public static class COMMON
    {
        [DllImport("winmm.dll")]
        public static extern uint timeGetTime();

        public const string Png = "PNG Portable Network Graphics (*.png)|" + "*.png";
        public const string Jpg = "JPEG File Interchange Format (*.jpg *.jpeg *jfif)|" + "*.jpg;*.jpeg;*.jfif";
        public const string Bmp = "BMP Windows Bitmap (*.bmp)|" + "*.bmp";
        public const string Tif = "TIF Tagged Imaged File Format (*.tif *.tiff)|" + "*.tif;*.tiff";
        public const string Gif = "GIF Graphics Interchange Format (*.gif)|" + "*.gif";
        public const string AllImages = "Image file|" + "*.png; *.jpg; *.jpeg; *.jfif; *.bmp;*.tif; *.tiff; *.gif";
        public const string AllFiles = "All files (*.*)" + "|*.*";

        public static string[] mediaExtensions = {
        ".PNG", ".JPG", ".JPEG", ".BMP", ".GIF", //etc
        ".WAV", ".MID", ".MIDI", ".WMA", ".MP3", ".OGG", ".RMA", //etc
        ".AVI", ".MP4", ".DIVX", ".WMV", //etc 
        };

        public static DataTable ConvertCSVtoDataTable(string strFilePath, string strSetHeader)
        {
            DataTable dt = null;
            try
            {
                using (StreamReader sr = new StreamReader(strFilePath))
                {
                    string[] headers = null;

                    if (strSetHeader.Length > 0)
                        headers = strSetHeader.Split(',');
                    else
                        headers = sr.ReadLine().Split(',');

                    dt = new DataTable();
                    foreach (string header in headers)
                    {
                        dt.Columns.Add(header);
                    }
                    while (!sr.EndOfStream)
                    {
                        string strReadData = sr.ReadLine().Trim();
                        if (strReadData.Length <= 0)
                            break;

                        string[] rows = Regex.Split(strReadData, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
                        DataRow dr = dt.NewRow();
                        for (int i = 0; i < headers.Length; i++)
                        {
                            dr[i] = rows[i];
                        }
                        dt.Rows.Add(dr);
                    }
                }
            }
            catch (Exception e)
            {
                dt = null;
            }

            return dt;
        }

        public static T ConvertTextToTryValue<T>(string strText, object objFailValue)
        {
            object obj;
            obj = typeof(T);

            int iGetValue = 0;
            uint uiGetValue = 0;
            double dGetValue = 0;

            if (obj.ToString().IndexOf("Int") >= 0)
            {
                if (!int.TryParse(strText, out iGetValue))
                    obj = objFailValue;
                else
                    obj = iGetValue;
            }
            if (obj.ToString().IndexOf("UInt") >= 0)
            {
                if (!uint.TryParse(strText, out uiGetValue))
                    obj = objFailValue;
                else
                    obj = uiGetValue;
            }
            else if (obj.ToString().IndexOf("Double") >= 0)
            {
                if (!double.TryParse(strText, out dGetValue))
                    obj = objFailValue;
                else
                    obj = dGetValue;
            }

            return (T)Convert.ChangeType(obj, typeof(T));
        }

        public static T FindByName<T>(this object targetClass, string name) where T : class
        {
            System.Reflection.FieldInfo fi = targetClass.GetType().GetField(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

            return fi.GetValue(targetClass) as T;
        }

        public static T FindByName<T>(this string name, object targetClass) where T : class
        {
            System.Reflection.FieldInfo fi = targetClass.GetType().GetField(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

            return fi.GetValue(targetClass) as T;
        }

        public class LogProcessInfo
        {
            public bool READ_INFO_STATE { set; get; }

            private string strInfoFilePos;

            public string TITLE;

            public string SERVER_SAVE_POS;
            public string MES_SAVE_POS;

            //TODO : Server ALIS FTP 
            public bool FTP_Use;

            public string FTP_IPAddress;
            public string FTP_Port;
            public string FTP_Account;
            public string FTP_Password;

            public long FTP_ScanTime_ms;

            public long BULK_ProcessTime_ms;

            public LogProcessInfo(string strGetInfoPath)
            {
                strInfoFilePos = strGetInfoPath;
            }
            public bool Load()
            {
                READ_INFO_STATE = true;

                try
                {
                    XDocument xDoc = XDocument.Load(strInfoFilePos);
                    var xElement = xDoc.Element("ROOT");

                    if (xElement != null)
                    {
                        var xGetElement = xElement.Element("Configure");

                        TITLE = xGetElement.Element("Title").Value;

                        SERVER_SAVE_POS = @xGetElement.Element("LogFileSavePos").Value;
                        MES_SAVE_POS = @xGetElement.Element("MESFileSavePos").Value;

                        //TODO : Server ALIS FTP
                        XElement xEle = xGetElement.Element("UseFTP");

                        bool bValue;
                        long lValue;
                        //string strValue;

                        if (xEle?.IsEmpty == false)
                        {
                            if (bool.TryParse(xEle.Value, out bValue))
                                FTP_Use = bValue;
                        }
                        else
                            FTP_Use = false;

                        xEle = xGetElement.Element("IPAddressFTP");

                        if (xEle?.IsEmpty == false)
                            FTP_IPAddress = xEle.Value;
                        else
                            FTP_IPAddress = "0.0.0.0";

                        xEle = xGetElement.Element("PortFTP");

                        if (xEle?.IsEmpty == false)
                            FTP_Port = xEle.Value;
                        else
                            FTP_Port = "21";

                        xEle = xGetElement.Element("AccountFTP");

                        if (xEle?.IsEmpty == false)
                            FTP_Account = xEle.Value;
                        else
                            FTP_Account = "";

                        xEle = xGetElement.Element("PasswordFTP");

                        if (xEle?.IsEmpty == false)
                            FTP_Password = xEle.Value;
                        else
                            FTP_Password = "";

                        xEle = xGetElement.Element("ScanTimeFTPms");

                        if (xEle?.IsEmpty == false)
                        {
                            if (long.TryParse(xEle.Value, out lValue))
                                FTP_ScanTime_ms = lValue;
                        }
                        else
                            FTP_ScanTime_ms = 30000;

                        xEle = xGetElement.Element("ScanTimeBULKms");

                        if (xEle?.IsEmpty == false)
                        {
                            if (long.TryParse(xEle.Value, out lValue))
                                BULK_ProcessTime_ms = lValue;
                        }
                        else
                            BULK_ProcessTime_ms = 30000;

                        if (Base.CheckPath(SERVER_SAVE_POS))
                        {
                            if (Directory.Exists(SERVER_SAVE_POS) == false)
                                Directory.CreateDirectory(SERVER_SAVE_POS);
                        }
                        else
                        {
                            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ServerInfo read failed.(SERVER SAVE POS - Folder name error)[SystemX.Common : SystemX.Net.ServerInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                            throw new Exception();
                        }

                        if (Base.CheckPath(MES_SAVE_POS))
                        {
                            if (Directory.Exists(MES_SAVE_POS) == false)
                                Directory.CreateDirectory(MES_SAVE_POS);
                        }
                        else
                        {
                            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ServerInfo read failed.(MES SAVE POS - Folder name error)[SystemX.Common : SystemX.Net.ServerInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                            throw new Exception();
                        }

                    }
                }
                catch (Exception e)
                {
                    READ_INFO_STATE = false;

                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"LogProcessInfo read failed. [LogProcessInfo : SystemX.Net.Middleware.Commons]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }

                return READ_INFO_STATE;
            }
        }
    }
}
