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

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 DevExpress.Utils.Extensions;
using System.Threading.Tasks;

using SystemX.Common.Protocol.SIA;

using static SystemX.Net.Platform.Common.Util.LogMessage;
using System.Threading;
using SystemX.Net.MiddlewareUI.UIM.Protocol_Method;

using static SystemX.Net.DB.XDBConnManager;

namespace SystemX.Net.MiddlewareUI
{
    public partial class MainForm : DevExpress.XtraBars.FluentDesignSystem.FluentDesignForm
    {
        private async void WatchRecvCommandQueue()
        {
            await Task.Delay(250);

            while (!m_bTaskCommandBlock)
            {
                try
                {
                    CT.ThrowIfCancellationRequested();
                }
                catch (OperationCanceledException CancelEx)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" Work Canceled. [SystemX.Net.MiddlewareUI : MainForm.WatchRecvCommndQueue]\r\n" + CancelEx.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                    break;
                }
                //
                try
                {
                    if (bTaskCommandWaitLock == false) QueryRecvCommandQueue();
                }
                catch (Exception e)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"General Queue Process failed.[1] [SystemX.Net.MiddlewareUI : MainForm.WatchRecvCommndQueue]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }
                try
                {
                    if (MngDBConn.GetMainDBAccessTime() >= 120000)
                    {
                        //lock (objSingleTransactionDataAccessWait)
                        {
                            QueryCommandProcess(eConnCategory.Main, "SELECT GETDATE() AS 'CHECK PING';");
                        }
                    }
                    if (MngDBConn.GetShortTermDBAccessTime() >= 120000)
                    {
                        //lock (objSingleTransactionDataAccessWait)
                        {
                            QueryCommandProcess(eConnCategory.ShortTerm, "SELECT GETDATE() AS 'CHECK PING';");
                        }
                    }
                    if (MngDBConn.GetLongTermDBAccessTime() >= 120000)
                    {
                        //lock (objSingleTransactionDataAccessWait)
                        {
                            QueryCommandProcess(eConnCategory.LongTerm, "SELECT GETDATE() AS 'CHECK PING';");
                        }
                    }
                    /*
                     For TestList Update Check 
                     */
                    for (int i = PORT_DISTRIBUTION_NUM; i < ALL_MANAGE_NUM; i++)
                    {
                        if (thisConnInfo[i].ClientConnectState == false)
                            continue;

                        foreach (var valuePair in thisTLLoadInfo[i].dicTLInfo)
                        {
                            if (valuePair.Value.bLoaded == false)
                                continue;

                            if (valuePair.Value.GetLoadedTime() <= 60000)
                                continue;

                            CustomProtocol_ cp = new CustomProtocol_();
                            string strGetQuery = cp.CheckTestListUpdate(valuePair.Value.strProdNo_C, valuePair.Value.strTestCode, valuePair.Value.strTestType, valuePair.Value.strVersion, valuePair.Value.strProdCode);

                            DataSet ds = null;

                            //lock (objSingleTransactionDataAccessWait)
                            {
                                ds = QueryCommandProcess(eConnCategory.Main, strGetQuery);
                            }

                            if (XCommons.isHasRow(ds) == false)
                                continue;

                            int nGetStationID = Convert.ToInt32(valuePair.Key.Split(';')[2]);

                            DateTime getTestListFileUpdateDT = Convert.ToDateTime(ds.Tables[0].Rows[0]["TestListFileUpdateDT"]);

                            if (valuePair.Value.TestListFileUpdateDT != getTestListFileUpdateDT)
                                SendClientAlarmUsePingPacket(i, "TLRL;" + nGetStationID.ToString("D2"));

                            valuePair.Value.SetLoadedTime();
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"General Queue Process failed.[2] [SystemX.Net.MiddlewareUI : MainForm.WatchRecvCommndQueue]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }

                await Task.Delay(10);
            }

            //return m_bTaskCommandBlock;
        }
        //private async void SendCommandEvent(byte[] senderData, ScheduleEvent e)
        private void SendCommandEvent(byte[] senderData, ScheduleEvent e)
        {
            try
            {
                int iGetCall = e.CALL_NUMBER;

                if (thisConnInfo[e.CALL_NUMBER].m_ucSendCommandToken == 0x00)
                    thisConnInfo[e.CALL_NUMBER].m_ucSendCommandToken = 0x01;
                else if(thisConnInfo[e.CALL_NUMBER].m_ucSendCommandToken == 0x01)
                    thisConnInfo[e.CALL_NUMBER].m_ucSendCommandToken = 0x02;
                else
                    thisConnInfo[e.CALL_NUMBER].m_ucSendCommandToken = 0x01;

                thisConnInfo[e.CALL_NUMBER].m_iSendCommandCnt++;

                if (thisConnInfo[e.CALL_NUMBER].m_iSendCommandCnt + 1 == int.MaxValue)
                    thisConnInfo[e.CALL_NUMBER].m_iSendCommandCnt = 0;

                if (FlowCommandControl[iGetCall] == null)
                    return;

                //소켓 샌드 행위 내부 결과
                if (e.PROCESS_RESULT == false)
                {
                    //해당 패킷 횟수 상승 일단 회 차시 기록남기고 드랍
                    FlowCommandControl[iGetCall].SendPacketCycle();
                }
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"General <SendCommandEvent> failed.[SystemX.Net.MiddlewareUI : MainForm.SendCommandEvent]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
        }
        //private async void RecvCommandEvent(byte[] senderData, ScheduleEvent e)
        private void RecvCommandEvent(byte[] senderData, ScheduleEvent e)
        {
            try
            {
                int iGetCall = e.CALL_NUMBER;

                if (thisConnInfo[e.CALL_NUMBER].m_ucRecvCommandToken == 0x00)
                    thisConnInfo[e.CALL_NUMBER].m_ucRecvCommandToken = 0x01;
                else if (thisConnInfo[e.CALL_NUMBER].m_ucRecvCommandToken == 0x01)
                    thisConnInfo[e.CALL_NUMBER].m_ucRecvCommandToken = 0x02;
                else
                    thisConnInfo[e.CALL_NUMBER].m_ucRecvCommandToken = 0x01;

                thisConnInfo[e.CALL_NUMBER].m_iRecvCommandCnt++;

                if (thisConnInfo[e.CALL_NUMBER].m_iRecvCommandCnt + 1 == int.MaxValue)
                    thisConnInfo[e.CALL_NUMBER].m_iRecvCommandCnt = 0;

                if (FlowCommandControl[iGetCall] == null)
                    return;

                int iStoreCnt = senderData.Count();
                byte[] recvStoreBuffer = senderData;

                //소켓 리시브 행위 결과 전송
                if (e.PROCESS_RESULT == false)
                {
                    //받기 실패 단순 실패 응답
                    FlowCommandControl[iGetCall].InsertSendQueue(DateTime.Now, XCommons.SetSimpleResponsPacket(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.SIMPLE_RESPONSE), false), null, false, false);
                }
                else
                {
                    BASE_PROTOCOL GET_PROTOCOL = XCommons.GetHeaderProtocol(iStoreCnt, recvStoreBuffer);
                    BASE_PROTOCOL.PROTOCOL_CODE GET_CODE = GET_PROTOCOL.GET_CURRENT_PROTOCOL;

                    //응답
                    if (GET_CODE == BASE_PROTOCOL.PROTOCOL_CODE.SIMPLE_RESPONSE)
                    {
                        if (XCommons.GetSimpleResponsResult(iStoreCnt, recvStoreBuffer))
                            FlowCommandControl[iGetCall].SetSendPacketDrop();
                        else
                            FlowCommandControl[iGetCall].SendPacketCycle();
                    }
                    //파일 끝 응답
                    else if (GET_CODE == BASE_PROTOCOL.PROTOCOL_CODE.RAW_END)
                    {
                        if (XCommons.GetSimpleResponsResult(iStoreCnt, recvStoreBuffer))
                            FlowCommandControl[iGetCall].RawStoreQueuePOP();
                        else
                            FlowCommandControl[iGetCall].RawStoreQueuePOP();
                    }
                    //일반 응답
                    else
                    {
                        //성공 응답 
                        FlowCommandControl[iGetCall].InsertSendQueue(DateTime.Now, XCommons.SetSimpleResponsPacket(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.SIMPLE_RESPONSE), true), null, false, false);

                        //받은 큐에 넣어놓기
                        FlowCommandControl[iGetCall].InsertRecvQueue(senderData, null, e.nLABEL);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"General <RecvCommandEvent> failed.[SystemX.Net.MiddlewareUI : MainForm.RecvCommandEvent]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
        }

        private bool QueryRecvCommandProcess(int iFlowPos, string strProcessInfo)
        {
            int i = iFlowPos;

            bool bState = true;
            //
            XData getXData = FlowCommandControl[i].GetResultPacketData();

            if (getXData == null)
                return false;

            try
            {
                thisConnInfo[i].stCommandProcessTime.Restart();

                BASE_PROTOCOL GET_PROTOCOL = getXData.BaseProtocol;
                BASE_PROTOCOL.PROTOCOL_CODE CODE = GET_PROTOCOL.GET_CURRENT_PROTOCOL;

                HEADER_PACKET getHeader = getXData.HeaderPacket;
                object objData = getXData.objData;

                byte ucGetLabel = getXData.nLabel;

                bool bUseLabel = true;

                ProtocolShell PS = null;

                switch (CODE)
                {
                    case BASE_PROTOCOL.PROTOCOL_CODE.CONNECT_STATE:
                        PS = new CONNECT_STATE(this, i, ucGetLabel);
                        PS.ExecuteProtocol(GET_PROTOCOL,
                                   CODE,
                                   getHeader,
                                   objData);
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.DATASET_TRANSEFER:
                        {
                            DataSet ds = null;

                            if (getXData.bReplayResult) //Query 성공
                                ds = objData as DataSet;
                            else                        //Query 실패
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessInfo + @" PROTOCOL_CODE.DATASET_TRANSEFER Fail.[SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandQueue]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.HOST_INFO_CHECK:
                        if (LoadInfo.USE_HOST_INFO)
                        {
                            PS = new HOST_INFO_CHECK(this, i, ucGetLabel);
                            PS.ExecuteProtocol(GET_PROTOCOL,
                                       CODE,
                                       getHeader,
                                       objData);
                            bUseLabel = false;
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.PROCESS_QUERY:
                        PS = new PROCESS_QUERY(this, i, ucGetLabel);
                        PS.ExecuteProtocol(GET_PROTOCOL,
                                   CODE,
                                   getHeader,
                                   objData);
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.SYSTEM_QUERY:
                        PS = new SYSTEM_QUERY(this, i, ucGetLabel);
                        PS.ExecuteProtocol(GET_PROTOCOL,
                                   CODE,
                                   getHeader,
                                   objData);
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.USER_QUERY:
                        PS = new USER_QUERY(this, i, ucGetLabel);
                        PS.ExecuteProtocol(GET_PROTOCOL,
                                   CODE,
                                   getHeader,
                                   objData);
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.ETC:
                        {
                            try
                            {
                                USER_PACKET CustomPacket = (USER_PACKET)objData;
                            }
                            catch (Exception e)
                            {
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessInfo + @" <BASE_PROTOCOL.PROTOCOL_CODE.ETC:> Recv queue process fail.[SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandQueue]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                            }
                            finally
                            { }
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.INITILALIZE_INFO:
                        {
                            COMM_INFO_PACKET usPacket = (COMM_INFO_PACKET)objData;

                            if (ServerCommandSock[i].SOCK_TYPE == SOCKET_TYPE.TCP)
                            {
                                stWatchInitialTime[i].Restart();
                                m_bInitialCallState[i] = false;

                                InitializePortDistributionInfoSend(i, "MANUAL", false, PacketFlowControl.CommInfoManualToken);

                                thisConnInfo[i].ClientConnectState = false;
                            }
                            else if (ServerCommandSock[i].SOCK_TYPE == SOCKET_TYPE.UDP)
                            {
                                ServerCommandSock[i].strSetRemoteAddress = usPacket.objConnLocalAddress[0].Data;
                                ServerCommandSock[i].strSetRemotePort = usPacket.objConnLocalPort[0].Data;

                                stWatchInitialTime[i].Restart();
                                m_bInitialCallState[i] = true;

                                ConnPool[i].ConnWaitTimerReset();

                                thisConnInfo[i].Initialize();

                                thisConnInfo[i].ClientConnectState = true;
                            }
                        }
                        break;
                }

                if (ServerCommandSock[i].CLIENT_CONNECT && PS != null)
                {
                    if (PS.GetShellSendOnState())
                    {
                        if (PS.nByteListSize > 0 && PS.IsByteList)
                        {
                            DateTime dtSendTime = DateTime.Now;
                            for (int j = 0; j < PS.nByteListSize; j++)
                            {
                                if (FlowStreamControl[i].InsertSendQueue(dtSendTime, PS.ArrSendByte(j), null, ucGetLabel, true, true) == PacketFlowControl.CommonErrCode)
                                    throw new Exception();
                            }
                        }
                        else
                        {
                            if (PS.ArrSendByte() != null)
                            {
                                if (bUseLabel)
                                    FlowCommandControl[i].InsertSendQueue(DateTime.Now, PS.ArrSendByte(), null, ucGetLabel);
                                else
                                    FlowCommandControl[i].InsertSendQueue(DateTime.Now, PS.ArrSendByte(), null, false);
                            }
                        }
                    }
                }

                thisConnInfo[i].lCommandTime = thisConnInfo[i].stCommandProcessTime.ElapsedMilliseconds;
            }
            catch (Exception e)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessInfo + @" Recv queue process fail.[SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandProcess]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                bState = false;
            }

            return bState;
        }
        private bool QueryRecvCommandQueue()
        {
            bool bState = true;

            string strProcessDebugInfo = "[Unknown]";

            try
            {
                bTaskCommandWaitLock = true;

                //Port-distribution
                for (int i = 0; i < PORT_DISTRIBUTION_NUM; i++)
                {
                    if (m_bTaskCommandBlock)
                        break;
                    if (ListenServerOnState[i] == false)
                        continue;

                    //0 ~ 10 : Listen Distribution
                    if (m_bInitialCallState[i])
                    {
                        if (stWatchInitialTime[i].ElapsedMilliseconds >= 100)
                        {
                            stWatchInitialTime[i].Restart();
                            m_bInitialCallState[i] = false;

                            InitializePortDistributionInfoSend(i, "AUTO", false, PacketFlowControl.CommInfoAutoToken);

                            thisConnInfo[i].ClientConnectState = false;
                        }
                    }

                    if (ServerCommandSock[i] == null)
                        continue;
                    if (FlowCommandControl[i] == null)
                        continue;
                    if (FlowCommandControl[i].GetCurrentRecvProcessData() != null)
                        continue;

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

                    bState = QueryRecvCommandProcess(i, strProcessDebugInfo);

                    /*
                    else
                    {
                        if (thisConnInfo[i].ClientConnectState)
                        {
                            if (stWatchInitialTime[i].ElapsedMilliseconds >= 5000)
                            {
                                stWatchInitialTime[i].Restart();

                                InitializePortDistributionInfoSend(i, true);
                            }
                        }
                    }
                    */
                }

                //Process
                for (int i = PORT_DISTRIBUTION_NUM; i < ALL_MANAGE_NUM && !m_bTaskCommandBlock; i++)
                {
                    if (ServerCommandSock[i] == null)
                        continue;
                    else {
                        if (ServerCommandSock[i].CLIENT_CONNECT == false) {
                            if (ConnPool[i].bLastConnState)
                                continue;

                            if (ConnPool[i].ConnWaitTime() >= 90000) { 
                                //RemoveElement(i);

                                ClearServerInstance(i);

                                ConnPool[i].Initialize();
                            }
                        }
                    }
                    //
                    if (FlowCommandControl[i] == null)
                        continue;
                    if (FlowCommandControl[i].GetCurrentRecvProcessData() != null)
                        continue;
                    //
                    if (m_bInitialCallState[i])
                    {
                        //접속 후 1초 뒤 Initial
                        if (stWatchInitialTime[i].ElapsedMilliseconds >= 1000)
                        {
                            m_bInitialCallState[i] = false;

                            InitializeInfoSend(i);
                        }
                    }
                    //
                    thisConnInfo[i].m_iSendCommandQueueSize = FlowCommandControl[i].GetSendQueueSize();
                    thisConnInfo[i].m_iRecvCommandQueueSize = FlowCommandControl[i].GetRecvQueueSize();

                    if ((thisConnInfo[i].m_iSendCommandQueueSize + 1) == int.MaxValue)
                        thisConnInfo[i].m_iSendCommandQueueSize = 0;
                    if ((thisConnInfo[i].m_iRecvCommandQueueSize + 1) == int.MaxValue)
                        thisConnInfo[i].m_iRecvCommandQueueSize = 0;

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

                    bState = QueryRecvCommandProcess(i, strProcessDebugInfo);
                }
            }
            catch (Exception e)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + strProcessDebugInfo + @" Recv queue process fail.[SystemX.Net.MiddlewareUI : MainForm.QueryRecvCommandQueue]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                bState = false;
            }
            finally
            {
                bTaskCommandWaitLock = false;

                nCommandNumber++;

                if (nCommandNumber >= ALL_MANAGE_NUM)
                    nCommandNumber = 0;
            }

            return bState;
        }
    }
}
