using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Data.SqlTypes;

using DevExpress.Utils.DPI;
using DevExpress.Utils.Helpers;
using DevExpress.Data;
using DevExpress.Data.Helpers;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Navigation;

using SystemX.Net;
using SystemX.Common;
using SystemX.Net.BaseProtocol;
using SystemX.Net.Comm;
using SystemX.Net.Schedule;
using SystemX.Net.DB;
using SystemX.Common.Serialization;
using SystemX.Common.Archive;
using SystemX.Net.Platform.Common.Util;
using SystemX.Net.Platform.Common.ExtensionMethods;
using SystemX.Common.Log.Query;

using SystemX.Common.Protocol.SIA;

using SystemX.Common.Log.SIA;
using SystemX.Common.Log.LSU;

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

using SystemX.Net.Middleware.Commons;
using SystemX.Net.Platform.SystemX.Common;
using System.Collections.Concurrent;

namespace SystemX.Net.MiddlewareUI
{
    public interface ILogin
    {
        void SetLoginState(string strGetHostID, string strGetSection, bool bState);
    }

    public partial class MainForm : DevExpress.XtraBars.FluentDesignSystem.FluentDesignForm, ILogin
    {
        private const int SC_CLOSE = 0xF060;
        private const int MF_ENABLED = 0x0;
        private const int MF_GRAYED = 0x1;
        private const int MF_DISABLED = 0x2;

        [DllImport("user32.dll")]
        private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
        [DllImport("user32.dll")]
        private static extern int EnableMenuItem(IntPtr hMenu, int wIDEnableItem, int wEnable);

        /// <summary>
        /// Base Variable
        /// </summary>
        private const int ALL_MANAGE_NUM = 110;

        private const int PORT_DISTRIBUTION_NUM = 10;

        private bool MIDDLEWARE_START_STATE;

        private ServerInfo LoadInfo;

        private bool bUseMapLogProcess;

        private MapLogOption OptionMapLog;

        private CMapParameter ParamterMapLog;
        private CMapParameter ParamterMapInfoLog;

        public ServerInfo GetLoadSeverInfomation()
        {
            return LoadInfo;
        }

        /// <summary>
        /// Socket Comm
        /// </summary>
        private bool[] ProcessUseState;

        private AsyncServerSocket[] ServerCommandSock;
        private AsyncServerSocket[] ServerStreamSock;

        private PacketFlowControl[] FlowCommandControl;
        private PacketFlowControl[] FlowStreamControl;

        private TestListLoadInfo[] thisTLLoadInfo;
        private ConnectInfoStore[] thisConnInfo;

        private MngConnectionPool[] ConnPool;

        private bool[] ListenServerOnState;

        private bool bShowCpLogProcessTime { set; get; } = false;

        public object GetConnectInfo(int iPos)
        {
            return thisConnInfo[iPos];
        }

        public bool GetConnectInfoFindHost(string strHostName, string strSectionName, bool bUseUIM = false)
        {
            bool bFindResult = false;

            foreach (ConnectInfoStore cis in thisConnInfo)
            {
                if (cis.bHostLoginState == false)
                    continue;

                if (bUseUIM)
                {
                    if (cis.strConnectHostID.CompareTo(strHostName) == 0)
                    {
                        bFindResult = true;

                        break;
                    }
                }
                else
                {
                    if (cis.strConnectHostID.CompareTo(strHostName) == 0 &&
                        cis.strConnectSection.CompareTo(strSectionName) == 0)
                    {
                        bFindResult = true;

                        break;
                    }
                }
            }

            return bFindResult;
        }


        //RecvCommandQueue Task
        private Stopwatch stCheckReleaseTime;

        private Task taskRecvCommandProcess;
        private bool m_bTaskCommandBlock;

        //RecvStreamQueue Task
        private Task taskRecvStreamProcess;
        private bool m_bTaskStreamBlock;

        private Task taskMappedLogProcess;
        private bool m_bTaskMappedLogBlock;

        private ConcurrentQueue<Tuple<string, int, HEADER_PACKET, byte[]>> MappedLogQueueData;
        //
        CancellationTokenSource CTS;
        CancellationToken CT;

        /// <summary>
        /// ProcessInfo
        /// </summary>
        string[] strSetProcessInfo;

        private Stopwatch[] stWatchInitialTime;
        private bool[] m_bInitialCallState;
        private int[] nLastHandleNumber;
        //
        //private static readonly object objTaskCommandWait = new object();
        //private static readonly object objTaskStreamWait = new object();
        private static bool bTaskCommandWaitLock = false;
        private static bool bTaskStreamWaitLock = false;

        private static int nCommandNumber = 0;
        private static int nStreamNumber = 0;
        //
        //DataBase
        private XDBConnManager MngDBConn;

        public XDBConnManager GetDBConn()
        {
            return MngDBConn;
        }

        //LogProcess
        //private AnalysisLog_LSU LogTableQuery;
        private AnalysisLog_SIA LogTableQuery;
        private CallPreMadeQueryInfo xCallQuery;

        public CallPreMadeQueryInfo GetUsetQueryInfo()
        {
            return xCallQuery;
        }

        /// <summary>
        /// TimerLock
        /// </summary>
        private enum TIMER_LOCK
        {
            CHK_TIMER = 0,
            UI_TIMER = 1,
        }

        private bool[] m_bTimerLock;
        //
        private int m_iLastGetIndex;
        //
        XTableInfo getXTableInfo;

        private Task<bool> tkReset;
        //
        private static object objMainCommandWait = new object();
        private static object objShortTermCommandWait = new object();
        private static object objLongTermCommandWait = new object();

        private static object objMainStreamWait = new object();
        private static object objShortTermStreamWait = new object();
        private static object objLongTermStreamWait = new object();

        private static object objExcuteMainCommandWait = new object();
        private static object objExcuteShortTermCommandWait = new object();
        private static object objExcuteLongTermCommandWait = new object();

        private static object objExcuteMainStreamWait = new object();
        private static object objExcuteShortTermStreamWait = new object();
        private static object objExcuteLongTermStreamWait = new object();
        //
        //private static object objSingleTransactionDataAccessWait = new object();

        //private static object objClearServerInstanceWait = new object();

        private static int nMappedLogDataInOutFailedCnt = 0;

        //private static object objTestListCntIDLock = new object();

        public class CTestListCntID
        {
            public DateTime dtAccessTime;

            public int nCnt;

            public CTestListCntID()
            {
                dtAccessTime = DateTime.Now;

                nCnt = 1;
            }
        }

        //1 : Host-Section
        //2 : Id
        //3 : Time, Cnt
        private ConcurrentDictionary<string, ConcurrentDictionary<string, CTestListCntID>> dicQueryTestListCntID;

        public ConcurrentDictionary<string, ConcurrentDictionary<string, CTestListCntID>> TestListCntID
        {
            get
            {
                return dicQueryTestListCntID;
            }
        }

        /*
        private byte[] GetImageToByteArray(Bitmap bitMap)
        {
            return (byte[])ImgConverter.ConvertTo(bitMap, typeof(byte[]));
        }
        */

        public MainForm()
        {
            InitializeComponent();

            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                    @"Use CP-Server[X] Middleware Version for [CPXV2][v240529] " +
                    "[SystemX.Net.MiddlewareUI : MainForm]", ConsoleColor.Green, LogMessageLevel.FATAL);

            EnableMenuItem(GetSystemMenu(this.Handle, false), SC_CLOSE, MF_GRAYED);

            ConsoleUtil.ConsoleHide();

            MessageOutput.PrintLogLevel = LogMessageLevel.INFO;

            dicQueryTestListCntID = new ConcurrentDictionary<string, ConcurrentDictionary<string, CTestListCntID>>();

            CTS = new CancellationTokenSource();
            CT = CTS.Token;
            //
            tkReset = null;

            MIDDLEWARE_START_STATE = true;

            ServerCommandSock = new AsyncServerSocket[ALL_MANAGE_NUM];
            ServerStreamSock = new AsyncServerSocket[ALL_MANAGE_NUM];

            FlowCommandControl = new PacketFlowControl[ALL_MANAGE_NUM];
            FlowStreamControl = new PacketFlowControl[ALL_MANAGE_NUM];

            stWatchInitialTime = new Stopwatch[ALL_MANAGE_NUM];
            m_bInitialCallState = new bool[ALL_MANAGE_NUM];

            strSetProcessInfo = new string[ALL_MANAGE_NUM];

            nLastHandleNumber = new int[PORT_DISTRIBUTION_NUM];

            for (int i = 0; i < ALL_MANAGE_NUM; i++)
            {
                ServerCommandSock[i] = null;
                ServerStreamSock[i] = null;

                FlowCommandControl[i] = null;
                FlowStreamControl[i] = null;

                stWatchInitialTime[i] = new Stopwatch();
                stWatchInitialTime[i].Start();
                m_bInitialCallState[i] = false;

                strSetProcessInfo[i] = "";
            }

            string strExcutePos = Environment.CurrentDirectory;
            string strServerInfoPos = strExcutePos + @"\Configure\ServerInformation.xml";
            string strDBInfoPos = strExcutePos + @"\Configure\DBConnInfo.xml";
            string strMapLogOptionPos = strExcutePos + @"\Configure\MapLogOption.xml";

            ProcessUseState = new bool[ALL_MANAGE_NUM];
            Array.Clear(ProcessUseState, 0, ALL_MANAGE_NUM);

            OptionMapLog = new MapLogOption(strMapLogOptionPos);

            if (OptionMapLog.Load() == false)
            {
                MIDDLEWARE_START_STATE = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Failed to load map-log option information. [SystemX.Net.MiddlewareUI : MainForm.MainForm]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                return;
            }
            else
            {
                bUseMapLogProcess = OptionMapLog.bUseMapLog;

                barToggleSwitchItemMapLog.Checked = bUseMapLogProcess;

                ParamterMapLog = new CMapParameter();
                ParamterMapInfoLog = new CMapParameter();

                ParamterMapLog.strSetEnterMutexName = OptionMapLog.strMapLogEnterMutexName;
                ParamterMapLog.strSetAccessMutexName = OptionMapLog.strMapLogAccessMutexName;
                ParamterMapLog.strSetPath = OptionMapLog.strMapLogPath;
                ParamterMapLog.strSetFileName = OptionMapLog.strMapLogFileName;
                ParamterMapLog.strSetMapName = OptionMapLog.strMapLogName;

                ParamterMapInfoLog.strSetEnterMutexName = OptionMapLog.strMapInfoLogEnterMutexName;
                ParamterMapInfoLog.strSetAccessMutexName = OptionMapLog.strMapInfoLogAccessMutexName;
                ParamterMapInfoLog.strSetPath = OptionMapLog.strMapInfoLogPath;
                ParamterMapInfoLog.strSetFileName = OptionMapLog.strMapInfoLogFileName;
                ParamterMapInfoLog.strSetMapName = OptionMapLog.strMapInfoLogName;
            }

            LoadInfo = new ServerInfo(strServerInfoPos, ALL_MANAGE_NUM);

            if (LoadInfo.Load() == false)
            {
                MIDDLEWARE_START_STATE = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Failed to load server information. [SystemX.Net.MiddlewareUI : MainForm.MainForm]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                return;
            }
            else
            {
                string strGetTitle = this.Text;

                this.Text = strGetTitle + " " + (LoadInfo.LOOP_BACK ? " [LocalHost]" : " [" + LoadInfo.SERVER_IP + "]");

                Title_label.Text = "CP ALIS" + ((LoadInfo.TITLE.Length > 0) ? " [" + LoadInfo.TITLE + "]" : "");
            }

            thisTLLoadInfo = new TestListLoadInfo[ALL_MANAGE_NUM];
            thisConnInfo = new ConnectInfoStore[ALL_MANAGE_NUM];

            ConnPool = new MngConnectionPool[ALL_MANAGE_NUM];
            for (int i = 0; i < ALL_MANAGE_NUM; i++)
            {
                thisTLLoadInfo[i] = new TestListLoadInfo(0);
                thisConnInfo[i] = new ConnectInfoStore();

                thisConnInfo[i].bUseHostInfo = LoadInfo.USE_HOST_INFO;

                ConnPool[i] = new MngConnectionPool(i);
            }

            for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
            {
                ConnPool[i].bUseState = true;
                ConnPool[i].nUseCommandPort = LoadInfo.nListenCommandPort[i];
                ConnPool[i].nUseStreamPort = LoadInfo.nListenStreamPort[i];
                ConnPool[i].PortTImerRestart();
            }

            MngDBConn = new XDBConnManager();
            MngDBConn.ConfigPath = strDBInfoPos;
            if (MngDBConn.OpenConnection(LoadInfo.USE_HOST_INFO, LoadInfo.HOST_TABLE_NAME, LoadInfo.USER_TABLE_NAME))
            {
                getXTableInfo = MngDBConn.CurrentConnection(eConnCategory.Main).GetCollectSchemaInfo();

                //옵션 확인 및 ON
                //DECLARE @ARITHABORT VARCHAR(3) = 'OFF'; IF ( (64 & @@OPTIONS) = 64 ) SET @ARITHABORT = 'ON'; SELECT @ARITHABORT AS ARITHABORT;
                string strGetQuery1 = "DECLARE @ARITHABORT VARCHAR(3) = 'OFF'; IF ( (64 & @@OPTIONS) = 64 ) SET @ARITHABORT = 'ON'; SELECT @ARITHABORT AS ARITHABORT;";
                string strGetQuery2 = "DECLARE @ARITHIGNORE VARCHAR(3) = 'OFF'; IF ( (128 & @@OPTIONS) = 128 ) SET @ARITHIGNORE = 'ON'; SELECT @ARITHIGNORE AS ARITHIGNORE;";
                /*
                SET ARITHIGNORE ON

                 - 쿼리 실행 중 오버플로 또는 0으로 나누기 오류에서 오류 메시지를 반환할지 여부를 제어

　                 오류 메시지가 반환될지 여부만 제어하며 이 설정에 상관 없이 오버플로 또는 0으로 나누기 오류를  
　                 발생시킨 계산에 NULL을 반환한다. 없는 값 처리를 해야하므고 오류를 발생시킨 것에서  null 반환을 받아야 한다!

                SET ARITHABORT ON이면 오버플로 또는 0으로 나누기 오류 발생 시 쿼리나 일괄 처리가 종료 
　                 트랜잭션에서 해당 오류가 발생하면 트랜잭션이 롤백시킨다.  그러나 이 설정이 INSERT, UPDATE, DELETE 문 실행 중에  
　                 발생한 오류에는 영향을 주지 않는다.  
                */
                DataSet ds1 = MngDBConn.CurrentConnection(eConnCategory.Main).QueryDataSet(strGetQuery1);
                DataSet ds2 = MngDBConn.CurrentConnection(eConnCategory.Main).QueryDataSet(strGetQuery2);

                if (XCommons.isHasRow(ds1))
                {
                    bool bOptionState = ds1.Tables[0].Rows[0]["ARITHABORT"].ToString() == "ON" ? true : false;

                    if (bOptionState == false)
                        MngDBConn.CurrentConnection(eConnCategory.Main).QueryDataSet("SET ARITHABORT ON");
                }
                if (XCommons.isHasRow(ds2))
                {
                    bool bOptionState = ds2.Tables[0].Rows[0]["ARITHIGNORE"].ToString() == "ON" ? true : false;

                    if (bOptionState == false)
                        MngDBConn.CurrentConnection(eConnCategory.Main).QueryDataSet("SET ARITHIGNORE ON");
                }
                //
                ds1 = MngDBConn.CurrentConnection(eConnCategory.ShortTerm).QueryDataSet(strGetQuery1);
                ds2 = MngDBConn.CurrentConnection(eConnCategory.ShortTerm).QueryDataSet(strGetQuery2);

                if (XCommons.isHasRow(ds1))
                {
                    bool bOptionState = ds1.Tables[0].Rows[0]["ARITHABORT"].ToString() == "ON" ? true : false;

                    if (bOptionState == false)
                        MngDBConn.CurrentConnection(eConnCategory.ShortTerm).QueryDataSet("SET ARITHABORT ON");
                }
                if (XCommons.isHasRow(ds2))
                {
                    bool bOptionState = ds2.Tables[0].Rows[0]["ARITHIGNORE"].ToString() == "ON" ? true : false;

                    if (bOptionState == false)
                        MngDBConn.CurrentConnection(eConnCategory.ShortTerm).QueryDataSet("SET ARITHIGNORE ON");
                }
                //
                ds1 = MngDBConn.CurrentConnection(eConnCategory.LongTerm).QueryDataSet(strGetQuery1);
                ds2 = MngDBConn.CurrentConnection(eConnCategory.LongTerm).QueryDataSet(strGetQuery2);

                if (XCommons.isHasRow(ds1))
                {
                    bool bOptionState = ds1.Tables[0].Rows[0]["ARITHABORT"].ToString() == "ON" ? true : false;

                    if (bOptionState == false)
                        MngDBConn.CurrentConnection(eConnCategory.LongTerm).QueryDataSet("SET ARITHABORT ON");
                }
                if (XCommons.isHasRow(ds2))
                {
                    bool bOptionState = ds2.Tables[0].Rows[0]["ARITHIGNORE"].ToString() == "ON" ? true : false;

                    if (bOptionState == false)
                        MngDBConn.CurrentConnection(eConnCategory.LongTerm).QueryDataSet("SET ARITHIGNORE ON");
                }

                if (MIDDLEWARE_START_STATE == false)
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"The table registered in the configuration file does not exist in the actual database. [SystemX.Net.MiddlewareUI : MainForm.MainForm]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
            else
            {
                MIDDLEWARE_START_STATE = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Failed to connect to DB and to get table information. [SystemX.Net.MiddlewareUI : MainForm.MainForm]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                return;
            }

            m_bTimerLock = new bool[10];
            Array.Clear(m_bTimerLock, 0, 10);

            m_iLastGetIndex = -1;

            ClearServerInstance();

            if (StartListenServer(LoadInfo.nListenCommandPort, LoadInfo.nListenStreamPort) == false)
            {
                MIDDLEWARE_START_STATE = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"MiddlewareUI failed to start! [SystemX.Net.MiddlewareUI : MainForm.MainForm]", ConsoleColor.Red, LogMessageLevel.FATAL);

                return;
            }
            else
            {
                ListenServerOnState = new bool[PORT_DISTRIBUTION_NUM];

                for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
                    ListenServerOnState[i] = true;
            }

            if (MIDDLEWARE_START_STATE)
            {
                DisplayListenElement();

                DisplayPortElement();

                //Log Process Start
                try
                {
                    string strUserQueryInfoPos = strExcutePos + @"\Configure\CallMadeQueryInfo.xml";

                    xCallQuery = new CallPreMadeQueryInfo(strUserQueryInfoPos);
                    xCallQuery.Load();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                }
                //
                stCheckReleaseTime = new Stopwatch();
                stCheckReleaseTime.Start();

                taskRecvCommandProcess = null;
                m_bTaskCommandBlock = false;

                taskRecvCommandProcess = new Task(new Action(WatchRecvCommandQueue), CT);
                taskRecvCommandProcess.Start();
                //
                taskRecvStreamProcess = null;
                m_bTaskStreamBlock = false;

                taskRecvStreamProcess = new Task(new Action(WatchRecvStreamQueue), CT);
                taskRecvStreamProcess.Start();

                MappedLogQueueData = new ConcurrentQueue<Tuple<string, int, HEADER_PACKET, byte[]>>();

                taskMappedLogProcess = null;
                m_bTaskMappedLogBlock = false;

                taskMappedLogProcess = new Task(new Action(WatchMappedLogQueue), CT);
                taskMappedLogProcess.Start();
                //
                TimeControl.DoSyncTime(LoadInfo);

                UItimer.Enabled = true;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"MiddlewareUI start success. [SystemX.Net.MiddlewareUI : MainForm.MainForm]", ConsoleColor.White, LogMessageLevel.INFO);
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MIDDLEWARE_START_STATE == true)
            {
                if (MessageBox.Show("You want to program exit?", "Middleware for Line Bridge - Middleware.UI", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                    e.Cancel = true;
                else
                    e.Cancel = false;
            }
            else
                e.Cancel = false;
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            CTS.Cancel();

            if (taskRecvCommandProcess != null)
            {
                m_bTaskCommandBlock = true;

                taskRecvCommandProcess.Wait();
                taskRecvCommandProcess.ContinueWith(t =>
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"taskRecvCommandProcess END. [SystemX.Net.MiddlewareUI : MainForm.MainForm_FormClosed]",
                        ConsoleColor.White,
                        LogMessageLevel.DEBUG);
                });
            }

            if (taskRecvStreamProcess != null)
            {
                m_bTaskStreamBlock = true;

                taskRecvStreamProcess.Wait();
                taskRecvStreamProcess.ContinueWith(t =>
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"taskRecvStreamProcess END. [SystemX.Net.MiddlewareUI : MainForm.MainForm_FormClosed]",
                        ConsoleColor.White,
                        LogMessageLevel.DEBUG);
                });
            }

            if (taskMappedLogProcess != null)
            {
                m_bTaskMappedLogBlock = true;

                taskMappedLogProcess.Wait();
                taskMappedLogProcess.ContinueWith(t =>
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"taskMappedLogProcess END. [SystemX.Net.MiddlewareUI : MainForm.MainForm_FormClosed]",
                        ConsoleColor.White,
                        LogMessageLevel.DEBUG);
                });
            }
        }

        private void ClientConnectEvent(object sender, ScheduleEvent e)
        {
            string strGetLocalEndPoint = "<Unknown address>";

            try
            {
                strGetLocalEndPoint = ((Socket)sender)?.RemoteEndPoint?.ToString();

                if (strGetLocalEndPoint == null)
                    strGetLocalEndPoint = "<Unknown address>";
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client command-connection connect." + strGetLocalEndPoint + " LocalEndPoint error. [SystemX.Net.MiddlewareUI : MainForm.ClientConnectEvent]\r\n" + ex.Message, ConsoleColor.Red, LogMessageLevel.INFO);
            }

            try
            {
                thisConnInfo[e.CALL_NUMBER].strCommandEndPointInfo = strGetLocalEndPoint;
                //
                thisConnInfo[e.CALL_NUMBER].stStreamCheckTime.Restart();
                thisConnInfo[e.CALL_NUMBER].ConnectStreamCheck = true;
                //
                stWatchInitialTime[e.CALL_NUMBER].Restart();
                m_bInitialCallState[e.CALL_NUMBER] = true;

                ConnPool[e.CALL_NUMBER].bLastConnState = true;
                ConnPool[e.CALL_NUMBER].ConnWaitTimerReset();

                thisConnInfo[e.CALL_NUMBER].Initialize();

                thisConnInfo[e.CALL_NUMBER].ClientConnectState = true;
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client command-connection connect." + strGetLocalEndPoint + " Setting error. [SystemX.Net.MiddlewareUI : MainForm.ClientConnectEvent]\r\n" + ex.Message, ConsoleColor.White, LogMessageLevel.INFO);
            }

            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client command-connection connect." + strGetLocalEndPoint + " [SystemX.Net.MiddlewareUI : MainForm.ClientConnectEvent]", ConsoleColor.White, LogMessageLevel.INFO);
        }

        private void ClientErrorEvent(object sender, ScheduleEvent e)
        {
            try
            {
                thisConnInfo[e.CALL_NUMBER].ClientConnectState = false;
                thisConnInfo[e.CALL_NUMBER].bHostLoginState = false;

                stWatchInitialTime[e.CALL_NUMBER].Restart();

                if (e.CALL_NUMBER >= PORT_DISTRIBUTION_NUM)
                    SetLoginState(thisConnInfo[e.CALL_NUMBER].strConnectHostID, thisConnInfo[e.CALL_NUMBER].strConnectSection, false);

                thisTLLoadInfo[e.CALL_NUMBER].Initialize();

                thisConnInfo[e.CALL_NUMBER].strConnectHostID = "";
                thisConnInfo[e.CALL_NUMBER].strConnectSection = "";

                thisConnInfo[e.CALL_NUMBER].strCommandEndPointInfo = "";

                thisConnInfo[e.CALL_NUMBER].stStreamCheckTime.Restart();
                thisConnInfo[e.CALL_NUMBER].ConnectStreamCheck = false;
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client command-connection error." + thisConnInfo[e.CALL_NUMBER].strCommandEndPointInfo + " Setting error. [SystemX.Net.MiddlewareUI : MainForm.ClientErrorEvent]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
            finally
            {
                //thisConnInfo[e.CALL_NUMBER].ClientConnectSocket = null;

                if (e.CALL_NUMBER >= PORT_DISTRIBUTION_NUM)
                {
                    //RemoveElement(e.CALL_NUMBER);

                    ClearServerInstance(e.CALL_NUMBER);

                    ConnPool[e.CALL_NUMBER].Initialize();
                }
                else
                    ConnPool[e.CALL_NUMBER].bRequiredPortReset = true;

                //MakeServerInstance(e.CALL_NUMBER);
            }

            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client command-connection error." + thisConnInfo[e.CALL_NUMBER].strCommandEndPointInfo + " [SystemX.Net.MiddlewareUI : MainForm.ClientErrorEvent]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);
        }

        private void StreamConnectEvent(object sender, ScheduleEvent e)
        {
            string strGetLocalEndPoint = "<Unknown address>";

            try
            {
                strGetLocalEndPoint = ((Socket)sender)?.RemoteEndPoint?.ToString();

                if (strGetLocalEndPoint == null)
                    strGetLocalEndPoint = "<Unknown address>";
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client stream-connection connect." + strGetLocalEndPoint + " LocalEndPoint error. [SystemX.Net.MiddlewareUI : MainForm.StreamConnectEvent]\r\n" + ex.Message, ConsoleColor.Red, LogMessageLevel.INFO);
            }

            thisConnInfo[e.CALL_NUMBER].StreamConnectState = true;

            thisConnInfo[e.CALL_NUMBER].strStreamEndPointInfo = strGetLocalEndPoint;

            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client stream-connection connect." + thisConnInfo[e.CALL_NUMBER].strStreamEndPointInfo + " [SystemX.Net.MiddlewareUI : MainForm.StreamConnectEvent]", ConsoleColor.White, LogMessageLevel.INFO);
        }

        private void StreamErrorEvent(object sender, ScheduleEvent e)
        {
            MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client stream-connection error." + thisConnInfo[e.CALL_NUMBER].strStreamEndPointInfo + " [SystemX.Net.MiddlewareUI : MainForm.StreamErrorEvent]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

            thisConnInfo[e.CALL_NUMBER].StreamConnectState = false;

            thisConnInfo[e.CALL_NUMBER].strStreamEndPointInfo = "";
        }

        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (this.Visible)
                this.Visible = false;
            else
                this.Visible = true;
        }

        private void label1_DoubleClick(object sender, EventArgs e)
        {
            ConsoleUtil.ConsoleVisibleControl();
        }

        private void accordionControl_Click(object sender, EventArgs e)
        {
            if (m_iLastGetIndex != -1)
                m_iLastGetIndex = -1;
        }

        private void contextMenuSubStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            ToolStripItem tsi = e.ClickedItem;

            this.Close();
        }

        internal struct StationQueryTestListInfo
        {
            private Stopwatch stLoadedTimer { set; get; }

            public bool bLoaded { set; get; }

            public int nFileNo { set; get; }
            public int nVariantNo { set; get; }

            public string strProdNo_C { set; get; }
            public string strProdNo_P { set; get; }
            public DateTime UpdateDT { set; get; }
            public DateTime TestListFileUpdateDT { set; get; }
            public string strTestCode { set; get; }
            public string strTestType { set; get; }
            public string strVersion { set; get; }
            public string strProdCode { set; get; }

            public void SetLoadedTime()
            {
                stLoadedTimer.Restart();
            }

            public long GetLoadedTime()
            {
                return stLoadedTimer.ElapsedMilliseconds;
            }

            public StationQueryTestListInfo(int nOption)
            {
                stLoadedTimer = new Stopwatch();
                stLoadedTimer.Start();

                bLoaded = false;

                nFileNo = -1;

                nVariantNo = -1;

                strProdNo_C = "";
                strProdNo_P = "";

                UpdateDT = DateTime.Now;

                TestListFileUpdateDT = DateTime.Now;

                strTestCode = "";
                strTestType = "";
                strVersion = "";
                strProdCode = "";
            }
        }

        internal struct TestListLoadInfo
        {
            public ConcurrentDictionary<string, StationQueryTestListInfo> dicTLInfo;

            public TestListLoadInfo(int nOption)
            {
                dicTLInfo = new ConcurrentDictionary<string, StationQueryTestListInfo>();
            }

            public void Initialize()
            {
                if (dicTLInfo != null)
                {
                    if (dicTLInfo.Count > 0) dicTLInfo.Clear();
                }

                dicTLInfo = new ConcurrentDictionary<string, StationQueryTestListInfo>();
            }
        }
        //
        internal class ConnectInfoStore : ICloneable
        {
            /// <summary>
            /// Connect Socket Infomation
            /// </summary>
            /// 
            //public Socket ClientConnectSocket { set; get; }

            public bool ClientConnectState { set; get; }

            public bool ConnectStreamCheck { set; get; }
            public bool StreamConnectState { set; get; }

            public byte m_ucSendCommandToken { set; get; }
            public byte m_ucRecvCommandToken { set; get; }

            public byte m_ucSendStreamToken { set; get; }
            public byte m_ucRecvStreamToken { set; get; }

            public int m_iSendCommandCnt { set; get; }
            public int m_iRecvCommandCnt { set; get; }

            public int m_iSendStreamCnt { set; get; }
            public int m_iRecvStreamCnt { set; get; }

            public int m_iSendCommandQueueSize { set; get; }
            public int m_iRecvCommandQueueSize { set; get; }

            public int m_iSendStreamQueueSize { set; get; }
            public int m_iRecvStreamQueueSize { set; get; }

            /// <summary>
            /// Big Size File
            /// </summary>
            public List<Tuple<int, byte[]>> lstRecvFileBytes { set; get; }
            public int nFileRecvPos { set; get; }
            public int nFileRecvEndPos { set; get; }

            public string strRecvFileName { set; get; }
            public string strRecvFileExtension { set; get; }

            /// <summary>
            /// Last Process Time
            /// </summary>
            public Stopwatch stCommandProcessTime;
            public long lCommandTime;

            public Stopwatch stStreamProcessTime;
            public long lStreamTime;

            public Stopwatch stCheckTime;
            public Stopwatch stStreamCheckTime;

            /// <summary>
            /// Connect User Info
            /// </summary>
            public bool bUseHostInfo;
            public bool bHostLoginState;

            public string strConnectHostID;
            public string strConnectSection;

            public string strCommandEndPointInfo;
            public string strStreamEndPointInfo;

            public string strResultTestListCntID;

            /// <summary>
            /// Last Query Info
            /// </summary>
            public int iLastQueryTLStepVer;

            public bool bSuccessQueryVRFY;

            public DataSet getLatestStepVer;
            public DataSet geyLatestTestListInfo;

            public DataSet dsLatestVRFYRel;
            public DataSet dsLongTermLatestVRFYRel;

            public object Clone()
            {
                return this;
            }

            public void Initialize()
            {
                lstRecvFileBytes = new List<Tuple<int, byte[]>>();

                nFileRecvPos = 0;
                nFileRecvEndPos = 0;

                iLastQueryTLStepVer = int.MinValue;

                bSuccessQueryVRFY = false;

                getLatestStepVer = null;
                geyLatestTestListInfo = null;

                dsLatestVRFYRel = null;
                dsLongTermLatestVRFYRel = null;

                strResultTestListCntID = string.Empty;
            }

            public void InitVRFYStatus()
            {
                iLastQueryTLStepVer = int.MinValue;

                bSuccessQueryVRFY = false;

                getLatestStepVer = null;
                geyLatestTestListInfo = null;

                dsLatestVRFYRel = null;
                dsLongTermLatestVRFYRel = null;
            }

            public ConnectInfoStore()
            {
                //ClientConnectSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                //ClientConnectSocket = null;

                ClientConnectState = false;

                m_ucSendCommandToken = 0x0;
                m_ucRecvCommandToken = 0x0;

                m_ucSendStreamToken = 0x0;
                m_ucRecvStreamToken = 0x0;

                m_iSendCommandCnt = 0;
                m_iRecvCommandCnt = 0;

                m_iSendStreamCnt = 0;
                m_iRecvStreamCnt = 0;

                m_iSendCommandQueueSize = 0;
                m_iRecvCommandQueueSize = 0;

                m_iSendStreamQueueSize = 0;
                m_iRecvStreamQueueSize = 0;

                lstRecvFileBytes = new List<Tuple<int, byte[]>>();
                nFileRecvPos = 0;
                nFileRecvEndPos = 0;

                strRecvFileName = string.Empty;
                strRecvFileExtension = string.Empty;
                //
                stCommandProcessTime = new Stopwatch();
                stCommandProcessTime.Start();
                lCommandTime = 0;

                stStreamProcessTime = new Stopwatch();
                stStreamProcessTime.Start();
                lStreamTime = 0;

                stCheckTime = new Stopwatch();
                stCheckTime.Start();

                stStreamCheckTime = new Stopwatch();
                stStreamCheckTime.Start();
                //
                bUseHostInfo = false;
                bHostLoginState = false;

                strConnectHostID = "";
                strConnectSection = "";

                strCommandEndPointInfo = "";
                strStreamEndPointInfo = "";
                //
                iLastQueryTLStepVer = int.MinValue;

                bSuccessQueryVRFY = false;

                getLatestStepVer = null;
                geyLatestTestListInfo = null;

                dsLatestVRFYRel = null;
                dsLongTermLatestVRFYRel = null;

                strResultTestListCntID = string.Empty;
            }
        }

        private void barCheckItemShowCpLogTime_CheckedChanged(object sender, ItemClickEventArgs e)
        {
            bShowCpLogProcessTime = barCheckItemShowCpLogTime.Checked;
        }

        private void barButtonItemConsole_ItemClick(object sender, ItemClickEventArgs e)
        {
            Console.Clear();
        }

        private void barToggleSwitchItemMapLog_CheckedChanged(object sender, ItemClickEventArgs e)
        {
            bUseMapLogProcess = barToggleSwitchItemMapLog.Checked;
        }

        private void buttonMapLogClear_Click(object sender, EventArgs e)
        {
            if (MappedLogQueueData.IsEmpty == false)
                MappedLogQueueData = new ConcurrentQueue<Tuple<string, int, HEADER_PACKET, byte[]>>();
        }
    }
}
