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 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 System.Threading.Tasks;

using SystemX.Common.Protocol.SIA;

using static SystemX.Net.Platform.Common.Util.LogMessage;
using System.Threading;
using SystemX.Net.Platform.Common.ExtensionMethods;

using DevExpress.Data.Helpers;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Navigation;
using static SystemX.Net.DB.XDBConnManager;
using System.Net.NetworkInformation;
using System.Collections.Concurrent;

namespace SystemX.Net.MiddlewareUI
{
    public partial class MainForm : DevExpress.XtraBars.FluentDesignSystem.FluentDesignForm
    {
        public void SetLoginState(string strGetHostID, string strGetSection, bool bState)
        {
            //lock (objSingleTransactionDataAccessWait)
            {
                try
                {
                    CustomProtocol_ cp = new CustomProtocol_();

                    SqlCommand cmd = cp.LoginInfoSummaryInsert(strGetHostID, strGetSection, bState);

                    bool bProcessResult = ExcuteNonQueryCommandProcess(cmd);
                }
                catch (Exception ex)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" Login [ON] history process failed. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }
            }
        }

        private void SendClientAlarmUsePingPacket(int nConnPos, string strSetMessage)
        {
            PING_PACKET PingPacketMake = new PING_PACKET();
            int iSendSize = Marshal.SizeOf(PingPacketMake);
            byte[] ucSendArray = new byte[iSendSize];
            PingPacketMake = (PING_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, PingPacketMake.GetType());

            if (strSetMessage.Length > 8)
                strSetMessage = strSetMessage.Substring(0, 8);

            PingPacketMake.objCheckMsg[0].Data = strSetMessage;

            byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.CONNECT_STATE), PingPacketMake);

            if (ServerCommandSock[nConnPos].CLIENT_CONNECT)
            {
                if (ucSendByteInfo != null)
                    FlowCommandControl[nConnPos].InsertSendQueue(DateTime.Now, ucSendByteInfo, null, false);
            }
        }

        public bool ReadVRFYList(int nConnId, int nTestListFileNo, int nTestListVariantNo, string strProcessDebugInfo, out int nReadStepVersion, /*int nSetReadStepVersion,*/ int nLoadPosition = 0, bool bForceRead = true)
        {
            nReadStepVersion = int.MaxValue;

            try
            {
                try
                {
                    //해당 테스트리스 정보 마지막 업데이트 번호 가져오기
                    thisConnInfo[nConnId].getLatestStepVer = QueryStreamProcess(eConnCategory.Main, "SELECT LatestStepVersion FROM [HIST_TestListFileLatestStepVersion] WITH(NOLOCK) WHERE TestListFileNo = " + nTestListFileNo + ";");

                    nReadStepVersion = Convert.ToInt32(thisConnInfo[nConnId].getLatestStepVer.Tables[0].Rows[0]["LatestStepVersion"]);
                }
                catch
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo +
                       @" CpLogProcess [HIST_TestListFileLatestStepVersion] MSV failed to obtain the most recent update number for VRFY (VRFY could not be found with the loading test list information.). [SystemX.Net.MiddlewareUI : MainForm.ReadVRFYList]", ConsoleColor.Red, LogMessageLevel.FATAL);

                    throw new Exception();
                }

                //이전 버전 사용 일시
                if (nLoadPosition > 0)
                    nReadStepVersion -= nLoadPosition;

                /* Changed
                 * 마지막 업데이트 번호가 다를때만 테스트리스트(VRFY) 갱신(Enabled Step 별 가장 최근 업데이트 번호 목록 정리)
                 * > 항상 최근 해당 테스트리스트(VRFY) 조회로 변경 
                 * > 매번 조회시 속도 문제로 동일한 VRFY일 경우 SKIP
                 * > INDEX 사용
                */
                if (bForceRead || (thisConnInfo[nConnId].bSuccessQueryVRFY == false || thisConnInfo[nConnId].iLastQueryTLStepVer != nReadStepVersion))
                {
                    try
                    {
                        /*thisConnInfo[nConnId].dsLatestVRFYRel = QueryStreamProcess(eConnCategory.Main, "SELECT * FROM ( " +
                            "SELECT *, ROW_NUMBER() OVER(PARTITION BY StepID ORDER BY StepVersion DESC) " +
                            "AS RN FROM [VRFY_TestListFileRelease] WITH (NOLOCK, INDEX=[CSK_VRFY_Release_2]) WHERE TestListFileNo = " + nTestListFileNo + " " +
                            "AND Enable = 1 AND StepVersion <= " + nReadStepVersion + ") X WHERE RN = 1 ORDER BY X.StepID ASC;");*/

                        string strQueryVRFY = "SELECT * FROM ( " +
                            "SELECT *, ROW_NUMBER() OVER(PARTITION BY StepID ORDER BY StepVersion DESC) " +
                            "AS RN FROM [VRFY_TestListFileRelease] WITH (NOLOCK, INDEX=[CSK_VRFY_Release_2]) WHERE TestListFileNo = " + nTestListFileNo + " " +
                            "AND StepVersion <= " + nReadStepVersion + ") X WHERE RN = 1 ORDER BY X.StepID ASC;";

                        thisConnInfo[nConnId].dsLatestVRFYRel = QueryStreamProcess(eConnCategory.Main, strQueryVRFY);

                        thisConnInfo[nConnId].dsLongTermLatestVRFYRel = thisConnInfo[nConnId].dsLatestVRFYRel.Copy();

                        DataColumn[] keys1 = new DataColumn[1];
                        keys1[0] = new DataColumn();
                        keys1[0] = thisConnInfo[nConnId].dsLatestVRFYRel.Tables[0].Columns["StepID"];

                        thisConnInfo[nConnId].dsLatestVRFYRel.Tables[0].PrimaryKey = keys1;

                        DataColumn[] keys2 = new DataColumn[1];
                        keys2[0] = new DataColumn();
                        keys2[0] = thisConnInfo[nConnId].dsLongTermLatestVRFYRel.Tables[0].Columns["StepID"];

                        thisConnInfo[nConnId].dsLongTermLatestVRFYRel.Tables[0].PrimaryKey = keys2;

                        thisConnInfo[nConnId].iLastQueryTLStepVer = nReadStepVersion;

                        thisConnInfo[nConnId].bSuccessQueryVRFY = true;
                    }
                    catch
                    {
                        MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo +
                           @" CpLogProcess Failed to get list from [VRFY_TestListFileRelease]. [SystemX.Net.MiddlewareUI : MainForm.ReadVRFYList]", ConsoleColor.Red, LogMessageLevel.FATAL);

                        throw new Exception();
                    }
                }
            }
            catch
            {
                return false;
            }

            return true;
        }

        public string SetQueryTestListInfo(int nConnId, string strGetHostID, string strGetSection, PROCESS_PACKET getPacket, DataSet getQuerySet)
        {
            string strSetQueryTestListCntID = string.Empty;

            string strProcessDebugInfo = string.Empty;
            strProcessDebugInfo = "[" + (nConnId).ToString("D2") + "]" +
                "[" + ConnPool[nConnId].nUseCommandPort + "]" +
                "[" + thisConnInfo[nConnId].strConnectHostID + "]" +
                "[" + thisConnInfo[nConnId].strConnectSection + "]";

            CustomProtocol_ cp = new CustomProtocol_();

            int nSetResult = -1;

            string strProdNoP = "-";
            string strFileName = "-";

            int nTestListFileNo = -1;
            int nTestListVariantNo = -1;

            if (XCommons.isHasRow(getQuerySet) == false)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info history process [DataSet] failed. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                nSetResult = 0;

                goto QUERY_TESTLIST_RESULT;
            }
            //
            if (getQuerySet.Tables[0].Rows.Count != 1)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info history process [DataSet Rows] failed. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                thisConnInfo[nConnId].InitVRFYStatus();

                nSetResult = 2;

                goto QUERY_TESTLIST_RESULT;
            }
            //
            try
            {
                strProdNoP = getQuerySet.Tables[0].Rows[0]["ProdNo_P"].ToString();
                strFileName = getQuerySet.Tables[0].Rows[0]["FileName"].ToString();

                string strHostSectionInfo =
                thisConnInfo[nConnId].strConnectHostID + ";" +
                thisConnInfo[nConnId].strConnectSection;

                string strMakeCntID =
                getPacket.objProdNo_C[0].Data + ";" +
                getPacket.objTestType[0].Data + ";" +
                getPacket.objTestCode[0].Data + ";" +
                getPacket.objTestListFileVersion[0].Data + ";" +
                getPacket.objProductionCode[0].Data;// + ";" +
                                                    //strFileName;

                if (dicQueryTestListCntID.ContainsKey(strHostSectionInfo))
                {
                    CTestListCntID refTempInfo = null;
                    DateTime dtStandardTime = DateTime.Now;

                    if (dicQueryTestListCntID[strHostSectionInfo].ContainsKey(strMakeCntID))
                    {
                        dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].dtAccessTime = dtStandardTime;
                        dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].nCnt += 1;
                    }
                    else
                    {
                        if (dicQueryTestListCntID[strHostSectionInfo].TryAdd(strMakeCntID, new CTestListCntID()))
                        {
                            dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].dtAccessTime = dtStandardTime;
                            dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].nCnt = 1;
                        }
                    }

                    //해당 호스트 섹션 기준 등록되는 시간보다 오래된 아이템 삭제
                    string[] strGetDeleteID = new string[dicQueryTestListCntID[strHostSectionInfo].Count];
                    for (int i = 0; i < dicQueryTestListCntID[strHostSectionInfo].Count; i++)
                    {
                        strGetDeleteID[i] = string.Empty;

                        if (dicQueryTestListCntID[strHostSectionInfo].ElementAt(i).Value.dtAccessTime < dtStandardTime)
                            strGetDeleteID[i] = dicQueryTestListCntID[strHostSectionInfo].ElementAt(i).Key;
                    }
                    //삭제
                    for (int i = 0; i < strGetDeleteID.Count(); i++)
                    {
                        if (string.IsNullOrEmpty(strGetDeleteID[i]) == false)
                        {
                            if (dicQueryTestListCntID[strHostSectionInfo].ContainsKey(strGetDeleteID[i]))
                                dicQueryTestListCntID[strHostSectionInfo].TryRemove(strGetDeleteID[i], out refTempInfo);
                        }
                    }
                }
                else
                {
                    if (dicQueryTestListCntID.TryAdd(strHostSectionInfo, new ConcurrentDictionary<string, CTestListCntID>()))
                    {
                        dicQueryTestListCntID[strHostSectionInfo].TryAdd(strMakeCntID, new CTestListCntID());
                        dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].dtAccessTime = DateTime.Now;
                        dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].nCnt = 1;
                    }
                }

                strSetQueryTestListCntID = dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].dtAccessTime.ToString("yyyyMMddHHmmssfff") + "@" +
                   dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].nCnt.ToString();

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info [" + strMakeCntID + "][" + strSetQueryTestListCntID + "]\r\n", ConsoleColor.DarkCyan, LogMessageLevel.DEBUG);

                nSetResult = 1;
            }
            catch (Exception ex)
            {
                strSetQueryTestListCntID = string.Empty;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info history process [Make TL ID] failed. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                nSetResult = 3;
            }
            //
            try
            {
                if (nSetResult != 1)
                {
                    throw new Exception("<Exception [SQT] Failed>");
                }

                nTestListFileNo = Convert.ToInt32(getQuerySet.Tables[0].Rows[0]["TestListFileNo"].ToString());
                nTestListVariantNo = Convert.ToInt32(getQuerySet.Tables[0].Rows[0]["VariantNo"].ToString());
                int nLoadPosition = Convert.ToInt32(getQuerySet.Tables[0].Rows[0]["UseTLPosition"]);

                uint nGetStationID = getPacket.nStationID;

                string strHostSectionInfo =
                    thisConnInfo[nConnId].strConnectHostID + ";" +
                    thisConnInfo[nConnId].strConnectSection;
                strHostSectionInfo += (";" + nGetStationID.ToString("D2"));

                StationQueryTestListInfo refSQL = new StationQueryTestListInfo(0);

                if (thisTLLoadInfo[nConnId].dicTLInfo.ContainsKey(strHostSectionInfo))
                    thisTLLoadInfo[nConnId].dicTLInfo.TryRemove(strHostSectionInfo, out refSQL);

                StationQueryTestListInfo SQT = new StationQueryTestListInfo(0);

                SQT.nFileNo = nTestListFileNo;
                SQT.nVariantNo = nTestListVariantNo;
                SQT.strProdNo_C = getQuerySet.Tables[0].Rows[0]["ProdNo_C"].ToString();
                SQT.strProdNo_P = strProdNoP;
                SQT.UpdateDT = Convert.ToDateTime(getQuerySet.Tables[0].Rows[0]["UpdateDT"]);
                SQT.TestListFileUpdateDT = Convert.ToDateTime(getQuerySet.Tables[0].Rows[0]["TestListFileUpdateDT"]);
                SQT.strTestCode = getQuerySet.Tables[0].Rows[0]["TestCode"].ToString();
                SQT.strTestType = getQuerySet.Tables[0].Rows[0]["TestType"].ToString();
                SQT.strVersion = getQuerySet.Tables[0].Rows[0]["Version"].ToString();
                SQT.strProdCode = getQuerySet.Tables[0].Rows[0]["ProdCode"].ToString();
                SQT.SetLoadedTime();
                SQT.bLoaded = true;

                //VRFY 조회
                /*
                int nGetMaxStepVersion = int.MaxValue;

                if (ReadVRFYList(nConnId, nTestListFileNo, nTestListVariantNo, strProcessDebugInfo, out nGetMaxStepVersion, nLoadPosition) == false)
                {
                    nSetResult = 0;

                    throw new Exception("Failed ReadVRFYList()");
                }
                */

                thisTLLoadInfo[nConnId].dicTLInfo.TryAdd(strHostSectionInfo, SQT);
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info [SQT] failed. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                nSetResult = 3;
            }
            //
    QUERY_TESTLIST_RESULT:
            try
            {
                //cp.QueryTestListInfoSummaryInsert(iLastNo, strGetHostID, strGetSection, strSetQueryTestListCntID,
                SqlCommand cmd = cp.QueryTestListInfoSummaryInsert(strGetHostID, strGetSection, strSetQueryTestListCntID,
                nSetResult,

                getPacket.objProdNo_C[0].Data,
                getPacket.objTestType[0].Data,
                getPacket.objTestListFileVersion[0].Data,
                getPacket.objProductionCode[0].Data,
                getPacket.objTestCode[0].Data,

                nTestListFileNo,
                nTestListVariantNo,
                strProdNoP,
                strFileName);

                bool bProcessResult = ExcuteNonQueryCommandProcess(cmd);
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info [QueryTestListInfoSummaryInsert] failed. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
            //
            if(strSetQueryTestListCntID == string.Empty)
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Query TestList Info empty. [SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

            if (nSetResult == 0)
                strSetQueryTestListCntID = "[FAIL]";
            else if (nSetResult == 2)
                strSetQueryTestListCntID = "[CHECK]";
            else if (nSetResult == 3)
                strSetQueryTestListCntID = "[ERROR]";

            return strSetQueryTestListCntID;
        }

        /*private void MakeServerInstance(int i)
        {
            IPAddress ServerIP = null;

            // 주소가 없다면. // 로컬호스트 주소를 사용한다.
            if (ServerIP == null)
                ServerIP = IPAddress.Loopback;

            if (LoadInfo.LOOP_BACK)
                ServerIP = IPAddress.Loopback;
            else
                ServerIP = IPAddress.Parse(LoadInfo.SERVER_IP);

            //COMMAND
            IPEndPoint ServerEP = new IPEndPoint(ServerIP, LoadInfo.ConnectInfo.ToList().ElementAt(i).nCommandPort);

            if (LoadInfo.USE_HOST_INFO)
                ServerCommandSock[i] = new AsyncServerSocket(i, ServerEP);//, MngDBConn.CurrentConnection().GetHostList());
            else
                ServerCommandSock[i] = new AsyncServerSocket(i, ServerEP);

            ServerCommandSock[i].Comm_Connect_Event += ClientConnectEvent;
            ServerCommandSock[i].Socket_Error_Event += ClientErrorEvent;

            ServerCommandSock[i].Comm_Send_Event += SendCommandEvent;
            ServerCommandSock[i].Comm_Recv_Event += RecvCommandEvent;

            FlowCommandControl[i] = new PacketFlowControl(FlowControlType.Commnad, ServerCommandSock[i]);

            //STREAM
            ServerEP = new IPEndPoint(ServerIP, LoadInfo.ConnectInfo.ToList().ElementAt(i).nStreamPort);

            if (LoadInfo.USE_HOST_INFO)
                ServerStreamSock[i] = new AsyncServerSocket(i, ServerEP);//, MngDBConn.CurrentConnection().GetHostList());
            else
                ServerStreamSock[i] = new AsyncServerSocket(i, ServerEP);

            ServerStreamSock[i].Comm_Connect_Event += StreamConnectEvent;
            ServerStreamSock[i].Socket_Error_Event += StreamErrorEvent;

            ServerStreamSock[i].Comm_Send_Event += SendStreamEvent;
            ServerStreamSock[i].Comm_Recv_Event += RecvStreamEvent;

            FlowStreamControl[i] = new PacketFlowControl(FlowControlType.Stream, ServerStreamSock[i]);
        }*/

        private void ClearServerInstance()
        {
            for (int i = 0; i < ALL_MANAGE_NUM; i++)
            {
                try
                {
                    //
                    if (ServerStreamSock[i] != null)
                    {
                        ServerStreamSock[i].Comm_Connect_Event -= StreamConnectEvent;
                        ServerStreamSock[i].Socket_Error_Event -= StreamErrorEvent;

                        ServerStreamSock[i].Comm_Send_Event -= SendStreamEvent;
                        ServerStreamSock[i].Comm_Recv_Event -= RecvStreamEvent;

                        ServerStreamSock[i].Dispose();
                        ServerStreamSock[i] = null;
                    }
                    ServerStreamSock[i] = null;
                    //
                    if (ServerCommandSock[i] != null)
                    {
                        ServerCommandSock[i].Comm_Connect_Event -= ClientConnectEvent;
                        ServerCommandSock[i].Socket_Error_Event -= ClientErrorEvent;

                        ServerCommandSock[i].Comm_Send_Event -= SendCommandEvent;
                        ServerCommandSock[i].Comm_Recv_Event -= RecvCommandEvent;

                        ServerCommandSock[i].Dispose();
                        ServerCommandSock[i] = null;
                    }
                    ServerCommandSock[i] = null;
                    //
                    if (FlowStreamControl[i] != null)
                    {
                        FlowStreamControl[i].Dispose();
                        FlowStreamControl[i] = null;
                    }
                    FlowStreamControl[i] = null;
                    //
                    if (FlowCommandControl[i] != null)
                    {
                        FlowCommandControl[i].Dispose();
                        FlowCommandControl[i] = null;
                    }
                    FlowCommandControl[i] = null;
                }
                catch (Exception ex)
                {
                    ServerStreamSock[i] = null;
                    ServerCommandSock[i] = null;

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

                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" ClearServerInstance() failed. [SystemX.Net.MiddlewareUI : MainForm.ClearServerInstance()]\r\n" + ex.Message, ConsoleColor.White, LogMessageLevel.INFO);
                }
            }
        }

        private void ClearServerInstance(int nPos)
        {
            //lock (objClearServerInstanceWait)
            {
                try
                {
                    //
                    if (ServerStreamSock[nPos] != null)
                    {
                        ServerStreamSock[nPos].Comm_Connect_Event -= StreamConnectEvent;
                        ServerStreamSock[nPos].Socket_Error_Event -= StreamErrorEvent;

                        ServerStreamSock[nPos].Comm_Send_Event -= SendStreamEvent;
                        ServerStreamSock[nPos].Comm_Recv_Event -= RecvStreamEvent;

                        ServerStreamSock[nPos].Dispose();
                        ServerStreamSock[nPos] = null;
                    }
                    ServerStreamSock[nPos] = null;
                    //
                    if (ServerCommandSock[nPos] != null)
                    {
                        ServerCommandSock[nPos].Comm_Connect_Event -= ClientConnectEvent;
                        ServerCommandSock[nPos].Socket_Error_Event -= ClientErrorEvent;

                        ServerCommandSock[nPos].Comm_Send_Event -= SendCommandEvent;
                        ServerCommandSock[nPos].Comm_Recv_Event -= RecvCommandEvent;

                        ServerCommandSock[nPos].Dispose();
                        ServerCommandSock[nPos] = null;
                    }
                    ServerCommandSock[nPos] = null;
                    //
                    if (FlowStreamControl[nPos] != null)
                    {
                        FlowStreamControl[nPos].Dispose();
                        FlowStreamControl[nPos] = null;
                    }
                    FlowStreamControl[nPos] = null;
                    //
                    if (FlowCommandControl[nPos] != null)
                    {
                        FlowCommandControl[nPos].Dispose();
                        FlowCommandControl[nPos] = null;
                    }
                    FlowCommandControl[nPos] = null;
                }
                catch (Exception ex)
                {
                    ServerStreamSock[nPos] = null;
                    ServerCommandSock[nPos] = null;

                    FlowStreamControl[nPos] = null;
                    FlowCommandControl[nPos] = null;

                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" ClearServerInstance(Pos) failed. [SystemX.Net.MiddlewareUI : MainForm.ClearServerInstance(Pos)]\r\n" + ex.Message, ConsoleColor.White, LogMessageLevel.INFO);
                }
                finally
                {
                    ;//
                }
            }
        }


        private void ClearListenServerInstance()
        {
            for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
            {
                if (ConnPool[i].bRequiredPortReset)
                    continue;

                try
                {
                    //
                    if (ServerStreamSock[i] != null)
                    {
                        ServerStreamSock[i].Comm_Connect_Event -= StreamConnectEvent;
                        ServerStreamSock[i].Socket_Error_Event -= StreamErrorEvent;

                        ServerStreamSock[i].Comm_Send_Event -= SendStreamEvent;
                        ServerStreamSock[i].Comm_Recv_Event -= RecvStreamEvent;

                        ServerStreamSock[i].Dispose();
                        ServerStreamSock[i] = null;
                    }
                    ServerStreamSock[i] = null;
                    //
                    if (ServerCommandSock[i] != null)
                    {
                        ServerCommandSock[i].Comm_Connect_Event -= ClientConnectEvent;
                        ServerCommandSock[i].Socket_Error_Event -= ClientErrorEvent;

                        ServerCommandSock[i].Comm_Send_Event -= SendCommandEvent;
                        ServerCommandSock[i].Comm_Recv_Event -= RecvCommandEvent;

                        ServerCommandSock[i].Dispose();
                        ServerCommandSock[i] = null;
                    }
                    ServerCommandSock[i] = null;
                    //
                    if (FlowStreamControl[i] != null)
                    {
                        FlowStreamControl[i].bTargetListenFlow = true;
                        FlowStreamControl[i].Dispose();
                        FlowStreamControl[i] = null;
                    }
                    FlowStreamControl[i] = null;
                    //
                    if (FlowCommandControl[i] != null)
                    {
                        FlowCommandControl[i].bTargetListenFlow = true;
                        FlowCommandControl[i].Dispose();
                        FlowCommandControl[i] = null;
                    }
                    FlowCommandControl[i] = null;
                }
                catch (Exception ex)
                {
                    ServerStreamSock[i] = null;
                    ServerCommandSock[i] = null;

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

                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" ClearListenServerInstance() failed. [SystemX.Net.MiddlewareUI : MainForm.ClearListenServerInstance()]\r\n" + ex.Message, ConsoleColor.White, LogMessageLevel.INFO);
                }
            }
        }

        private void ClearListenServerInstance(int nPos)
        {
            try
            {
                //
                if (ServerStreamSock[nPos] != null)
                {
                    ServerStreamSock[nPos].Comm_Connect_Event -= StreamConnectEvent;
                    ServerStreamSock[nPos].Socket_Error_Event -= StreamErrorEvent;

                    ServerStreamSock[nPos].Comm_Send_Event -= SendStreamEvent;
                    ServerStreamSock[nPos].Comm_Recv_Event -= RecvStreamEvent;

                    ServerStreamSock[nPos].Dispose();
                    ServerStreamSock[nPos] = null;
                }
                ServerStreamSock[nPos] = null;
                //
                if (ServerCommandSock[nPos] != null)
                {
                    ServerCommandSock[nPos].Comm_Connect_Event -= ClientConnectEvent;
                    ServerCommandSock[nPos].Socket_Error_Event -= ClientErrorEvent;

                    ServerCommandSock[nPos].Comm_Send_Event -= SendCommandEvent;
                    ServerCommandSock[nPos].Comm_Recv_Event -= RecvCommandEvent;

                    ServerCommandSock[nPos].Dispose();
                    ServerCommandSock[nPos] = null;
                }
                ServerCommandSock[nPos] = null;
                //
                if (FlowStreamControl[nPos] != null)
                {
                    FlowStreamControl[nPos].bTargetListenFlow = true;
                    FlowStreamControl[nPos].Dispose();
                    FlowStreamControl[nPos] = null;
                }
                FlowStreamControl[nPos] = null;
                //
                if (FlowCommandControl[nPos] != null)
                {
                    FlowCommandControl[nPos].bTargetListenFlow = true;
                    FlowCommandControl[nPos].Dispose();
                    FlowCommandControl[nPos] = null;
                }
                FlowCommandControl[nPos] = null;
            }
            catch (Exception ex)
            {
                ServerStreamSock[nPos] = null;
                ServerCommandSock[nPos] = null;

                FlowStreamControl[nPos] = null;
                FlowCommandControl[nPos] = null;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" ClearListenServerInstance(Pos) failed. [SystemX.Net.MiddlewareUI : MainForm.ClearListenServerInstance(Pos)]\r\n" + ex.Message, ConsoleColor.White, LogMessageLevel.INFO);
            }
        }

        private int GetCommandDistributionPort(Random r)
        {
            //최대값 미만 + 1
            r.Next();
            return r.Next(LoadInfo.nDistributionCommandStartPort, LoadInfo.nDistributionCommandEndPort + 1);
        }

        private int GetStreamDistributionPort(Random r)
        {
            //최대값 미만 + 1
            r.Next();
            return r.Next(LoadInfo.nDistributionStreamStartPort, LoadInfo.nDistributionStreamEndPort + 1);
        }

        private void GetCommandStreamPort(Random r, ref int nCommandPort, ref int nStreamPort)
        {
            while (true)
            {
                nCommandPort = GetCommandDistributionPort(r);
                nStreamPort = GetStreamDistributionPort(r);

                if (IsTcpPortAvailable(nCommandPort) == true &&
                   IsTcpPortAvailable(nStreamPort) == true)
                    break;
            }
        }

        private bool IsTcpPortAvailable(int tcpPort)
        {
            var ipgp = IPGlobalProperties.GetIPGlobalProperties();

            // Check ActiveConnection ports
            TcpConnectionInformation[] conns = ipgp.GetActiveTcpConnections();
            foreach (var cn in conns)
            {
                if (cn.LocalEndPoint.Port == tcpPort)
                    return false;
            }

            // Check LISTENING ports
            IPEndPoint[] endpoints = ipgp.GetActiveTcpListeners();
            foreach (var ep in endpoints)
            {
                if (ep.Port == tcpPort)
                    return false;
            }

            return true;
        }

        //private void InitializePortDistributionInfoSend(int nPos, bool bOnlyPortInfoSend = false)
        private void InitializePortDistributionInfoSend(int nPos, string strSendMsg, bool bOnlyPortInfoSend = false, byte nSetSendLabel = byte.MaxValue)
        {
            int nGetCommandPort = 0;
            int nGetStreamPort = 0;

            int nNum = 0;

            Random r = new Random((int)(DateTime.Now.Ticks));

            if (bOnlyPortInfoSend == false)
            {
                nNum = ConnPool.First(x => x.bUseState == false).nNumber;

                nLastHandleNumber[nPos] = nNum;

                GetCommandStreamPort(r, ref nGetCommandPort, ref nGetStreamPort);

                bool bCompareInfo = true;

                while (true)
                {
                    bCompareInfo = true;

                    for (int i = PORT_DISTRIBUTION_NUM; i < ALL_MANAGE_NUM; i++)
                    {
                        // 할당할 포트가 같은것이 존재
                        if (ConnPool[i].nUseCommandPort == nGetCommandPort ||
                           ConnPool[i].nUseStreamPort == nGetStreamPort)
                        {
                            // 연결상태가 아닐경우 
                            if (ConnPool[i].bUseState == false)
                            {
                                // 사용한지 5분이상 시 사용
                                if (ConnPool[i].stPortTimer.ElapsedMilliseconds >= 300000)
                                    break;
                            }

                            // 그외 재 할당 및 다시 확인
                            GetCommandStreamPort(r, ref nGetCommandPort, ref nGetStreamPort);

                            bCompareInfo = false;

                            break;
                        }
                    }

                    if (bCompareInfo)
                        break;
                }

                ConnPool[nNum].nUseCommandPort = nGetCommandPort;
                ConnPool[nNum].nUseStreamPort = nGetStreamPort;
                ConnPool[nNum].bUseState = true;
                ConnPool[nNum].ConnWaitTimerStart();

                StartConnectServer(nNum, nGetCommandPort, nGetStreamPort);

                AddElement(nNum, nGetCommandPort, nGetStreamPort);
            }

            thisConnInfo[nPos].m_ucSendCommandToken = 0x0;
            thisConnInfo[nPos].m_ucRecvCommandToken = 0x0;

            thisConnInfo[nPos].m_ucSendStreamToken = 0x0;
            thisConnInfo[nPos].m_ucRecvStreamToken = 0x0;

            thisConnInfo[nPos].m_iSendCommandCnt = 0;
            thisConnInfo[nPos].m_iRecvCommandCnt = 0;

            thisConnInfo[nPos].m_iSendStreamCnt = 0;
            thisConnInfo[nPos].m_iRecvStreamCnt = 0;

            COMM_INFO_PACKET ConnectCommSendInfo = new COMM_INFO_PACKET();
            int iSendSize = Marshal.SizeOf(ConnectCommSendInfo);
            byte[] ucSendArray = new byte[iSendSize];
            ConnectCommSendInfo = (COMM_INFO_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, ConnectCommSendInfo.GetType());

            ConnectCommSendInfo.bPortDistribution = true;

            ConnectCommSendInfo.usPortCommandNumber = (ushort)ConnPool[nNum].nUseCommandPort;
            ConnectCommSendInfo.usPortStreamNumber = (ushort)ConnPool[nNum].nUseStreamPort;
            ConnectCommSendInfo.objConnLocalAddress[0].Data = strSendMsg;
            ConnectCommSendInfo.objConnLocalPort[0].Data = "";

            byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.INITILALIZE_INFO), ConnectCommSendInfo);

            if (nSetSendLabel == byte.MaxValue)
                FlowCommandControl[nPos].InsertSendQueue(DateTime.Now, ucSendByteInfo, null);
            else
                FlowCommandControl[nPos].InsertSendQueue(DateTime.Now, ucSendByteInfo, null, nSetSendLabel);
        }

        private void InitializeInfoSend(int nPos)
        {
            thisConnInfo[nPos].m_iSendCommandCnt = 0;
            thisConnInfo[nPos].m_iRecvCommandCnt = 0;

            thisConnInfo[nPos].m_iSendStreamCnt = 0;
            thisConnInfo[nPos].m_iRecvStreamCnt = 0;

            thisConnInfo[nPos].m_ucSendCommandToken = 0x0;
            thisConnInfo[nPos].m_ucRecvCommandToken = 0x0;

            thisConnInfo[nPos].m_ucSendStreamToken = 0x0;
            thisConnInfo[nPos].m_ucRecvStreamToken = 0x0;

            COMM_INFO_PACKET ConnectCommSendInfo = new COMM_INFO_PACKET();
            int iSendSize = Marshal.SizeOf(ConnectCommSendInfo);
            byte[] ucSendArray = new byte[iSendSize];
            ConnectCommSendInfo = (COMM_INFO_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, ConnectCommSendInfo.GetType());

            ConnectCommSendInfo.bPortDistribution = false;

            ConnectCommSendInfo.usPortCommandNumber = (ushort)0;
            ConnectCommSendInfo.usPortStreamNumber = (ushort)0;
            ConnectCommSendInfo.objConnLocalAddress[0].Data = "";
            ConnectCommSendInfo.objConnLocalPort[0].Data = "";

            byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.INITILALIZE_INFO), ConnectCommSendInfo);

            FlowCommandControl[nPos].InsertSendQueue(DateTime.Now, ucSendByteInfo, null);
        }

        private void ListenServerReset()
        {
            for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
                ListenServerOnState[i] = false;

            Thread.Sleep(100);

            ClearListenServerInstance();

            if (StartListenServer(LoadInfo.nListenCommandPort, LoadInfo.nListenStreamPort))
                DisplayListenElement();

            for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
            {
                ConnPool[i].PortTImerRestart();

                ListenServerOnState[i] = true;
            }
        }

        private bool StartListenServer(int[] nListenCommandPort, int[] nListenStreamPort)
        {
            bool bServerStartState = true;

            try
            {
                IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName());
                IPAddress ServerIP = null;

                //ipv4 주소를 사용.
                foreach (IPAddress addr in he.AddressList)
                {
                    if (addr.AddressFamily == AddressFamily.InterNetwork)
                    {
                        ServerIP = addr;

                        break;
                    }
                }

                // 주소가 없다면. // 로컬호스트 주소를 사용한다.
                if (ServerIP == null)
                    ServerIP = IPAddress.Loopback;

                if (LoadInfo.LOOP_BACK)
                    ServerIP = IPAddress.Loopback;
                else
                    ServerIP = IPAddress.Parse(LoadInfo.SERVER_IP);

                IPEndPoint[] ServerCommandEP = new IPEndPoint[PORT_DISTRIBUTION_NUM];
                IPEndPoint[] ServerStreamEP = new IPEndPoint[PORT_DISTRIBUTION_NUM];

                for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
                {
                    ServerCommandEP[i] = new IPEndPoint(ServerIP, nListenCommandPort[i]);
                    ServerStreamEP[i] = new IPEndPoint(ServerIP, nListenStreamPort[i]);
                }

                for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
                {
                    //COMMAND
                    if (LoadInfo.USE_HOST_INFO)
                        ServerCommandSock[i] = new AsyncServerSocket(SOCKET_TYPE.TCP, i, ServerCommandEP[i]);
                    else
                        ServerCommandSock[i] = new AsyncServerSocket(SOCKET_TYPE.TCP, i, ServerCommandEP[i]);

                    ServerCommandSock[i].Comm_Connect_Event += ClientConnectEvent;
                    ServerCommandSock[i].Socket_Error_Event += ClientErrorEvent;

                    ServerCommandSock[i].Comm_Send_Event += SendCommandEvent;
                    ServerCommandSock[i].Comm_Recv_Event += RecvCommandEvent;

                    FlowCommandControl[i] = new PacketFlowControl(FlowControlType.Commnad, ServerCommandSock[i]);

                    //STREAM
                    /*
                    if (LoadInfo.USE_HOST_INFO)
                        ServerStreamSock[i] = new AsyncServerSocket(SOCKET_TYPE.TCP, i, ServerStreamEP[i]);//, MngDBConn.CurrentConnection().GetHostList());
                    else
                        ServerStreamSock[i] = new AsyncServerSocket(SOCKET_TYPE.TCP, i, ServerStreamEP[i]);

                    ServerStreamSock[i].Comm_Connect_Event += StreamConnectEvent;
                    ServerStreamSock[i].Socket_Error_Event += StreamErrorEvent;

                    ServerStreamSock[i].Comm_Send_Event += SendStreamEvent;
                    ServerStreamSock[i].Comm_Recv_Event += RecvStreamEvent;

                    FlowStreamControl[i] = new PacketFlowControl(FlowControlType.Stream, ServerStreamSock[i]);
                    */
                }
            }
            catch (Exception e)
            {
                bServerStartState = false;
            }

            if (bServerStartState)
            {
                //accordionControlElementConnectList.ImageOptions.Image = UIM.Properties.Resources.Bubble_32x32;
            }
            else
                ;//accordionControlElementConnectList.ImageOptions.Image = UIM.Properties.Resources.Cancel_32x32;

            return bServerStartState;
        }

        private bool StartListenServer(int nPos, int nSetListenCommandPort, int nSetListenStreamPort)
        {
            bool bServerStartState = true;

            try
            {
                IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName());
                IPAddress ServerIP = null;

                //ipv4 주소를 사용.
                foreach (IPAddress addr in he.AddressList)
                {
                    if (addr.AddressFamily == AddressFamily.InterNetwork)
                    {
                        ServerIP = addr;

                        break;
                    }
                }

                // 주소가 없다면. // 로컬호스트 주소를 사용한다.
                if (ServerIP == null)
                    ServerIP = IPAddress.Loopback;

                if (LoadInfo.LOOP_BACK)
                    ServerIP = IPAddress.Loopback;
                else
                    ServerIP = IPAddress.Parse(LoadInfo.SERVER_IP);

                IPEndPoint ServerCommandEP = new IPEndPoint(ServerIP, nSetListenCommandPort);
                IPEndPoint ServerStreamEP = new IPEndPoint(ServerIP, nSetListenStreamPort);

                //COMMAND
                if (LoadInfo.USE_HOST_INFO)
                    ServerCommandSock[nPos] = new AsyncServerSocket(SOCKET_TYPE.TCP, nPos, ServerCommandEP);
                else
                    ServerCommandSock[nPos] = new AsyncServerSocket(SOCKET_TYPE.TCP, nPos, ServerCommandEP);

                ServerCommandSock[nPos].Comm_Connect_Event += ClientConnectEvent;
                ServerCommandSock[nPos].Socket_Error_Event += ClientErrorEvent;

                ServerCommandSock[nPos].Comm_Send_Event += SendCommandEvent;
                ServerCommandSock[nPos].Comm_Recv_Event += RecvCommandEvent;

                FlowCommandControl[nPos] = new PacketFlowControl(FlowControlType.Commnad, ServerCommandSock[nPos]);

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

            return bServerStartState;
        }


        private bool StartConnectServer(int nPos, int nApplyCommandPort, int nApplyStreamPort)
        {
            bool bServerStartState = true;

            try
            {
                IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName());
                IPAddress ServerIP = null;

                //ipv4 주소를 사용.
                foreach (IPAddress addr in he.AddressList)
                {
                    if (addr.AddressFamily == AddressFamily.InterNetwork)
                    {
                        ServerIP = addr;

                        break;
                    }
                }

                ClearServerInstance(nPos);

                // 주소가 없다면. // 로컬호스트 주소를 사용한다.
                if (ServerIP == null)
                    ServerIP = IPAddress.Loopback;

                if (LoadInfo.LOOP_BACK)
                    ServerIP = IPAddress.Loopback;
                else
                    ServerIP = IPAddress.Parse(LoadInfo.SERVER_IP);

                IPEndPoint ServerCommandEP = new IPEndPoint(ServerIP, nApplyCommandPort);
                IPEndPoint ServerStreamEP = new IPEndPoint(ServerIP, nApplyStreamPort);

                //COMMAND
                if (LoadInfo.USE_HOST_INFO)
                    ServerCommandSock[nPos] = new AsyncServerSocket(SOCKET_TYPE.TCP, nPos, ServerCommandEP);
                else
                    ServerCommandSock[nPos] = new AsyncServerSocket(SOCKET_TYPE.TCP, nPos, ServerCommandEP);

                ServerCommandSock[nPos].Comm_Connect_Event += ClientConnectEvent;
                ServerCommandSock[nPos].Socket_Error_Event += ClientErrorEvent;

                ServerCommandSock[nPos].Comm_Send_Event += SendCommandEvent;
                ServerCommandSock[nPos].Comm_Recv_Event += RecvCommandEvent;

                FlowCommandControl[nPos] = new PacketFlowControl(FlowControlType.Commnad, ServerCommandSock[nPos]);

                //STREAM
                if (LoadInfo.USE_HOST_INFO)
                    ServerStreamSock[nPos] = new AsyncServerSocket(SOCKET_TYPE.TCP, nPos, ServerStreamEP);//, MngDBConn.CurrentConnection().GetHostList());
                else
                    ServerStreamSock[nPos] = new AsyncServerSocket(SOCKET_TYPE.TCP, nPos, ServerStreamEP);

                ServerStreamSock[nPos].Comm_Connect_Event += StreamConnectEvent;
                ServerStreamSock[nPos].Socket_Error_Event += StreamErrorEvent;

                ServerStreamSock[nPos].Comm_Send_Event += SendStreamEvent;
                ServerStreamSock[nPos].Comm_Recv_Event += RecvStreamEvent;

                FlowStreamControl[nPos] = new PacketFlowControl(FlowControlType.Stream, ServerStreamSock[nPos]);
            }
            catch (Exception e)
            {
                bServerStartState = false;
            }

            return bServerStartState;
        }

        private void ResetConnectSetCheck(int iPos)
        {
            if (tkReset == null)
            {
                Func<object, bool> func = (objParam) => { return ResetConnectSet((int)objParam).Result; };
                tkReset = new Task<bool>(func, iPos);
                tkReset.ContinueWith(t =>
                {
                    if (tkReset.IsCompleted)
                        tkReset = null;
                });
                tkReset.Start();
            }
        }

        private async Task<bool> ResetConnectSet(int iPos)
        {
            ServerStreamSock[iPos].ServerSocketAllClearToken();
            ServerCommandSock[iPos].ServerSocketAllClearToken();

            ServerStreamSock[iPos].ServerSocketUnknownError();
            ServerCommandSock[iPos].ServerSocketUnknownError();

            await Task.Delay(2000);

            //ClearServerInstance(iPos);

            //await Task.Delay(1000);

            //MakeServerInstance(iPos);

            return true;
        }

        private void ResetStreamConnectSetCheck(int iPos)
        {
            if (tkReset == null)
            {
                Func<object, bool> func = (objParam) => { return ResetStreamConnectSet((int)objParam).Result; };
                tkReset = new Task<bool>(func, iPos);
                tkReset.ContinueWith(t =>
                {
                    if (tkReset.IsCompleted)
                        tkReset = null;
                });
                tkReset.Start();
            }
        }

        private async Task<bool> ResetStreamConnectSet(int iPos)
        {
            ServerStreamSock[iPos].ServerSocketAllClearToken();
            ServerStreamSock[iPos].ServerSocketUnknownError();

            await Task.Delay(2000);

            //ClearServerInstance(iPos);

            //await Task.Delay(1000);

            //MakeServerInstance(iPos);

            return true;
        }
    }
}
