using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using SystemX.Net.BaseProtocol;

namespace SystemX.Net
{
    /// <summary>
    /// Num, Command Port, Stream Port, Use, ProcessCode, TestID, ProcessName, PLCCOnfilgFileName, PLCUseType
    /// </summary>
    //using PLC_DEVICE_BASE_CONFIG = Tuple<int, int, int, bool, int, string, string, Tuple<string, string>>;

    using static SystemX.Net.Platform.Common.Util.LogMessage;

    /// <summary>
    /// 
    /// </summary>
    public class PLCDeviceBaseConfig {
        public int nNum;
        public int nCommandPort;
        public int nStreamPort;
        public bool bUse;
        public int nProcessCode;
        public string strTestID;
        public string strProcessName;
        public string strPLCCOnfilgFileName;
        public string strPLCUseType;
    }

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

        private string strInfoFilePos;

        private int MAX_PROCESS_NUM;

        public string SERVER_IP;
        public bool LOOP_BACK;

        public string TITLE;

        public int[] nListenCommandPort;
        public int[] nListenStreamPort;

        public int nListenCommandPortNum;
        public int nListenCommandStartPort;
        public int nListenCommandEndPort;

        public int nListenStreamPortNum;
        public int nListenStreamStartPort;
        public int nListenStreamEndPort;

        public int nDistributionCommandPortNum;
        public int nDistributionCommandStartPort;
        public int nDistributionCommandEndPort;

        public int nDistributionStreamPortNum;
        public int nDistributionStreamStartPort;
        public int nDistributionStreamEndPort;

        public bool USE_HOST_INFO;
        public string HOST_TABLE_NAME;
        public string USER_TABLE_NAME;

        public string DISK_MONITOR_POS1;
        public string DISK_MONITOR_POS2;

        public string SERVER_SAVE_POS;
        public string MES_SAVE_POS;

        public string SyncTimeServerAddress;
        public int SyncTimeServerPort;
        public int TimeServerSyncTimeHour;
        public int TimeServerSyncTimeMinute;
        public int TimeServerSyncTimeSecond;

        public ServerInfo(string strGetInfoPath, int iMaxProcessNum)
        {
            strInfoFilePos = strGetInfoPath;

            MAX_PROCESS_NUM = iMaxProcessNum;
        }
        public bool Load()
        {
            READ_INFO_STATE = true;

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

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

                    SERVER_IP = xGetElement.Element("UseIP").Value;
                    iPort = Convert.ToInt32((xGetElement.Element("Port").Value.IndexOf("-") >= 0) ? "0" : xGetElement.Element("Port").Value);
                    LOOP_BACK = Convert.ToBoolean(xGetElement.Element("Loopback").Value);

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

                    nListenCommandStartPort = Convert.ToInt32(xGetElement.Element("ListenCommandPort").Attribute("Start").Value);
                    nListenCommandEndPort = Convert.ToInt32(xGetElement.Element("ListenCommandPort").Attribute("End").Value);

                    nListenCommandPortNum = nListenCommandEndPort - nListenCommandStartPort;

                    nListenStreamStartPort = Convert.ToInt32(xGetElement.Element("ListenStreamPort").Attribute("Start").Value);
                    nListenStreamEndPort = Convert.ToInt32(xGetElement.Element("ListenStreamPort").Attribute("End").Value);

                    nListenStreamPortNum = nListenStreamEndPort - nListenStreamStartPort;

                    nListenCommandPort = new int[nListenCommandPortNum];
                    nListenStreamPort = new int[nListenStreamPortNum];

                    for (int i = 0; i < nListenCommandPortNum; i++)
                        nListenCommandPort[i] = nListenCommandStartPort + i;

                    for (int i = 0; i < nListenStreamPortNum; i++)
                        nListenStreamPort[i] = nListenStreamStartPort + i;

                    nDistributionCommandStartPort = Convert.ToInt32(xGetElement.Element("DistributionCommandPort").Attribute("Start").Value);
                    nDistributionCommandEndPort = Convert.ToInt32(xGetElement.Element("DistributionCommandPort").Attribute("End").Value);

                    nDistributionCommandPortNum = nDistributionCommandEndPort - nDistributionCommandStartPort;

                    nDistributionStreamStartPort = Convert.ToInt32(xGetElement.Element("DistributionStreamPort").Attribute("Start").Value);
                    nDistributionStreamEndPort = Convert.ToInt32(xGetElement.Element("DistributionStreamPort").Attribute("End").Value);

                    nDistributionStreamPortNum = nDistributionStreamEndPort - nDistributionStreamStartPort;

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

                    USE_HOST_INFO = Convert.ToBoolean(xGetElement.Element("UseHostInfo").Value);
                    HOST_TABLE_NAME = @xGetElement.Element("HostInfoTableName").Value;
                    USER_TABLE_NAME = @xGetElement.Element("UserInfoTableName").Value;

                    DISK_MONITOR_POS1 = xGetElement.Element("DiskMonitor1").Value;
                    DISK_MONITOR_POS2 = xGetElement.Element("DiskMonitor2").Value;

                    if (DISK_MONITOR_POS1.Length <= 0)
                        DISK_MONITOR_POS1 = @"C:\";
                    if (DISK_MONITOR_POS2.Length <= 0)
                        DISK_MONITOR_POS2 = @"D:\";

                    SyncTimeServerAddress = xGetElement.Element("SyncTimeServerAddress").Attribute("Address").Value;

                    SyncTimeServerPort = int.MinValue;

                    if (int.TryParse(xGetElement.Element("SyncTimePort").Attribute("Port").Value, out SyncTimeServerPort) == false)
                        SyncTimeServerPort = int.MinValue;

                    TimeServerSyncTimeHour = 24;
                    TimeServerSyncTimeMinute = 0;
                    TimeServerSyncTimeSecond = 0;

                    if (int.TryParse(xGetElement.Element("TimeServer-SyncTime").Attribute("H").Value, out TimeServerSyncTimeHour) == false)
                        TimeServerSyncTimeHour = 24;
                    if (int.TryParse(xGetElement.Element("TimeServer-SyncTime").Attribute("M").Value, out TimeServerSyncTimeMinute) == false)
                        TimeServerSyncTimeMinute = 0;
                    if (int.TryParse(xGetElement.Element("TimeServer-SyncTime").Attribute("S").Value, out TimeServerSyncTimeSecond) == false)
                        TimeServerSyncTimeSecond = 0;     

                    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);

                            /*MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ServerInfo read failed.(MES SAVE POS - Folder exist error)[SystemX.Common : SystemX.Net.ServerInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                            throw new Exception();*/
                        }
                    }
                    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>>") + @"ServerInfo read failed.[SystemX.Common : SystemX.Net.ServerInfo]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return READ_INFO_STATE;
        }
    }

    public class MapLogOption
    {
        public bool bReadInfoState { set; get; }

        private string strInfoFilePos;

        public bool bUseMapLog;
        public string strMapLogEnterMutexName;
        public string strMapLogAccessMutexName;
        public string strMapLogPath;
        public string strMapLogFileName;
        public string strMapLogName;

        public string strMapInfoLogEnterMutexName;
        public string strMapInfoLogAccessMutexName;
        public string strMapInfoLogPath;
        public string strMapInfoLogFileName;
        public string strMapInfoLogName;

        public MapLogOption(string strGetInfoPath)
        {
            strInfoFilePos = strGetInfoPath;
        }
        public bool Load()
        {
            bReadInfoState = true;

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

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

                    XElement xEle = xGetElement.Element("UseMapLog");

                    if (xEle?.IsEmpty == false)
                        bUseMapLog = Convert.ToBoolean(xGetElement.Element("UseMapLog").Value);
                    else
                        bUseMapLog = false;

                    strMapLogEnterMutexName = xGetElement.Element("MapLogEnterMutexName").Value;
                    strMapLogAccessMutexName = xGetElement.Element("MapLogAccessMutexName").Value;
                    strMapLogPath = @xGetElement.Element("MapLogFilePath").Value;
                    strMapLogFileName = xGetElement.Element("MapLogFileName").Value;
                    strMapLogName = xGetElement.Element("MapLogName").Value;

                    strMapInfoLogEnterMutexName = xGetElement.Element("MapInfoLogEnterMutexName").Value;
                    strMapInfoLogAccessMutexName = xGetElement.Element("MapInfoLogAccessMutexName").Value;
                    strMapInfoLogPath = @xGetElement.Element("MapInfoLogFilePath").Value;
                    strMapInfoLogFileName = xGetElement.Element("MapInfoLogFileName").Value;
                    strMapInfoLogName = xGetElement.Element("MapInfoLogName").Value;

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

                        throw new Exception();
                    }

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

                        throw new Exception();
                    }
                }
            }
            catch (Exception e)
            {
                bReadInfoState = false;

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

            return bReadInfoState;
        }
    }

    /// <summary>
    /// PLC Device Base Infomation
    /// </summary>
    /// <param name="index"> Num, Port, Use, ProcessCode, TestID, ProcessName, PLCCOnfilgFileName </param>
    public class PLCBaseInfo {
        public bool READ_INFO_STATE { set; get; }
        private string strInfoFilePos;
        private int MAX_DEVICE_NUM;

        public string SERVER_IP;
        public bool LOOP_BACK;

        public PLCDeviceBaseConfig[] BaseInfo;

        public PLCBaseInfo(string strGetInfoPath, int iMaxDeviceNum) {
            strInfoFilePos = strGetInfoPath;

            MAX_DEVICE_NUM = iMaxDeviceNum;

            BaseInfo = new PLCDeviceBaseConfig[MAX_DEVICE_NUM];
        }
        public bool Load() {
            READ_INFO_STATE = true;

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

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

                    SERVER_IP = xGetElement.Element("UseIP").Value;
                    LOOP_BACK = Convert.ToBoolean(xGetElement.Element("Loopback").Value);

                    var ListGetElement = xElement.Elements("MiddlewareConnect").ToList();

                    foreach (var getXElement in ListGetElement) {
                        if (getXElement.Attribute("INFO")?.Value.CompareTo("COMMON") == 0) {
                            for (int i = 0; i < MAX_DEVICE_NUM; i++) {
                                BaseInfo[i] = new PLCDeviceBaseConfig();
                                BaseInfo[i].nNum = i;
                                BaseInfo[i].nCommandPort = Convert.ToInt32(getXElement.Element("Device" + (i + 1).ToString()).Attribute("Command_PortNumber").Value);
                                BaseInfo[i].nStreamPort = Convert.ToInt32(getXElement.Element("Device" + (i + 1).ToString()).Attribute("Stream_PortNumber").Value);
                                BaseInfo[i].bUse = Convert.ToBoolean(getXElement.Element("Device" + (i + 1).ToString()).Attribute("Use").Value);
                                BaseInfo[i].nProcessCode = Convert.ToInt32(getXElement.Element("Device" + (i + 1).ToString()).Attribute("ProcessCode").Value);
                                BaseInfo[i].strTestID = getXElement.Element("Device" + (i + 1).ToString()).Attribute("TestID").Value;
                                BaseInfo[i].strProcessName = getXElement.Element("Device" + (i + 1).ToString()).Attribute("ProcessName").Value;
                                BaseInfo[i].strPLCCOnfilgFileName = getXElement.Element("Device" + (i + 1).ToString()).Attribute("PLCConfigFileName").Value;
                                BaseInfo[i].strPLCUseType = getXElement.Element("Device" + (i + 1).ToString()).Attribute("PLCUseType").Value;
                            }
                        }
                    }
                }
            }
            catch (Exception e) {
                READ_INFO_STATE = false;

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

            return READ_INFO_STATE;
        }
    }
    /// <summary>
    /// PC Client Base Infomation
    /// </summary>
    public class ClientInfo {
        public bool READ_INFO_STATE { set; get; }
        private string strInfoFilePos;

        public string CONNECT_IP;

        public int COMMAND_PORT;
        public int STREAM_PORT;

        public bool LOOP_BACK;

        public string HOST_ID;
        public string SECTION;
        public string TEST_CODE;

        /* TODO : UIM Mode 및 기존 코드 정리 필요 */
        //SIMPLE_LOOKUP_OPTION
        //ISSUE_WORKER_WAIT_TIME_ms
        //SESSION_TIMEOUT_TIME_S
        //UIM
        public bool SIMPLE_LOOKUP_OPTION;
        public double ISSUE_WORKER_WAIT_TIME_ms;
        public double SESSION_TIMEOUT_TIME_S;

        //TODO : Client ALIS FTP 
        public bool FTP_Use;

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

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

            SIMPLE_LOOKUP_OPTION = false;

            ISSUE_WORKER_WAIT_TIME_ms = 3000.0;
            SESSION_TIMEOUT_TIME_S = 300.0;

            TEST_CODE = string.Empty;

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

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

                    CONNECT_IP = xGetElement.Element("UseIP").Value;

                    COMMAND_PORT = Convert.ToInt32((xGetElement.Element("CommandPort").Value.IndexOf("-") >= 0) ? "0" : xGetElement.Element("CommandPort").Value);
                    STREAM_PORT = Convert.ToInt32((xGetElement.Element("StreamPort").Value.IndexOf("-") >= 0) ? "0" : xGetElement.Element("StreamPort").Value);

                    LOOP_BACK = Convert.ToBoolean(xGetElement.Element("Loopback").Value);

                    HOST_ID = @xGetElement.Element("HostID").Value;
                    SECTION = @xGetElement.Element("Section").Value;

                    XElement xEle = xGetElement.Element("TestCode");

                    if (xEle?.IsEmpty == false)
                        TEST_CODE = @xGetElement.Element("TestCode").Value;

                    /*SCAN_LOG_FOLDER = Convert.ToBoolean(xGetElement.Element("LogFileScan").Value);
                    SCAN_LOG_FOLDER_POS = xGetElement.Element("LogFileScanPos").Value;

                    if (SCAN_LOG_FOLDER) {
                        if (Base.CheckPath(SCAN_LOG_FOLDER_POS)) {
                            if (Directory.Exists(SCAN_LOG_FOLDER_POS) == false) {
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ClientInfo read failed.(Scan log folder not exist)[SystemX.Common : SystemX.Net.ClientInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                                throw new Exception();
                            }
                        }
                        else {
                            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ClientInfo read failed.(Scan log folder name error)[SystemX.Common : SystemX.Net.ClientInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                            throw new Exception();
                        }
                    }

                    SCAN_DEVICE_FOLDER = Convert.ToBoolean(xGetElement.Element("DeviceFileScan").Value);
                    SCAN_DEVICE_FOLDER_TYPE = xGetElement.Element("DeviceFileScanType").Value;
                    SCAN_DEVICE_FOLDER_POS = xGetElement.Element("DeviceFileScanPos").Value;

                    if (SCAN_DEVICE_FOLDER) {
                        if (Base.CheckPath(SCAN_DEVICE_FOLDER_POS)) {
                            if (Directory.Exists(SCAN_DEVICE_FOLDER_POS) == false) {
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ClientInfo read failed.(Scan device folder not exist)[SystemX.Common : SystemX.Net.ClientInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                                throw new Exception();
                            }
                        }
                        else
                        {
                            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"ClientInfo read failed.(Scan device folder name error)[SystemX.Common : SystemX.Net.ClientInfo]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                            throw new Exception();
                        }
                    }*/

                    xEle = xGetElement.Element("SimpleLookUpOption");

                    bool bValue = false;
                    //string strValue;

                    if (xEle?.IsEmpty == false) {
                        if (bool.TryParse(xEle.Value, out bValue))
                            SIMPLE_LOOKUP_OPTION = Convert.ToBoolean(xEle.Value);
                    }

                    xEle = xGetElement.Element("IssueWorkerWaitTime_ms");

                    double dValue = double.NaN;

                    if (xEle?.IsEmpty == false) {          
                        if(double.TryParse(xEle.Value, out dValue))
                            ISSUE_WORKER_WAIT_TIME_ms = Convert.ToDouble(xEle.Value);
                    }

                    xEle = xGetElement.Element("SessionTimeout_s");

                    if (xGetElement.Element("SessionTimeout_s")?.IsEmpty == false) {
                        dValue = double.NaN;
                        if (double.TryParse(xEle.Value, out dValue))
                            SESSION_TIMEOUT_TIME_S = Convert.ToDouble(xEle.Value);
                    }

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

                    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 = "";
                }
            }
            catch (Exception e) {
                READ_INFO_STATE = false;

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

            return READ_INFO_STATE;
        }
    }
}
