using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SystemX.Common;
using SystemX.Net.BaseProtocol;
using SystemX.Net.XAdaptor.PC.O2Sensor.NgCode;
using SystemX.Net.Schedule;
using SystemX.Net.XAdaptor;
using static SystemX.Net.Platform.Common.Util.LogMessage;

namespace SystemX.Net.XAdaptor.PC
{
    public partial class XAdaptorPC
    {
        //private async void SendCommandEvent(byte[] senderData, ScheduleEvent e)
        private void SendCommandEvent(byte[] senderData, ScheduleEvent e)
        {
            try
            {
                thisConnInfo.m_iSendCommandCnt++;

                if (thisConnInfo.m_iSendCommandCnt + 1 == int.MaxValue)
                    thisConnInfo.m_iSendCommandCnt = 0;

                if (FlowCommandControl == null)
                    return;

                //소켓 샌드 행위 내부 결과
                if (e.PROCESS_RESULT == false)
                {
                    //해당 패킷 횟수 상승 일단 회 차시 기록남기고 드랍
                    FlowCommandControl.SendPacketCycle();
                }
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + 
                    @"General <SendCommandEvent> failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : 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
            {
                thisConnInfo.m_iRecvCommandCnt++;

                if (thisConnInfo.m_iRecvCommandCnt + 1 == int.MaxValue)
                    thisConnInfo.m_iRecvCommandCnt = 0;

                if (FlowCommandControl == null)
                    return;

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

                //소켓 리시브 행위 결과 전송
                if (e.PROCESS_RESULT == false)
                {
                    //받기 실패 단순 실패 응답
                    FlowCommandControl.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.SetSendPacketDrop();
                        else
                            FlowCommandControl.SendPacketCycle();
                    }
                    //파일 끝 응답
                    else if (GET_CODE == BASE_PROTOCOL.PROTOCOL_CODE.RAW_END)
                    {
                        if (XCommons.GetSimpleResponsResult(iStoreCnt, recvStoreBuffer))
                            FlowCommandControl.RawStoreQueuePOP();
                        else
                            FlowStreamControl.RawStoreQueuePOP();
                    }
                    //일반 응답
                    else
                    {
                        //성공 응답 
                        FlowCommandControl.InsertSendQueue(DateTime.Now, XCommons.SetSimpleResponsPacket(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.SIMPLE_RESPONSE), true), null, false, false);

                        //받은 큐에 넣어놓기
                        FlowCommandControl.InsertRecvQueue(senderData, null, e.nLABEL);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                    @"General <RecvCommandEvent> failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : RecvCommandEvent]\r\n" + ex.Message, 
                    ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
        }
        private async void WatchRecvCommandQueue()
        {
            await Task.Delay(250).ConfigureAwait(false);

            thisConnInfo.OnCommandTime();
            thisConnInfo.OnCommandCheckTime();

            while (!m_bTaskCommandBlock)
            {
                await Task.Delay(10).ConfigureAwait(false);

                try
                {
                    CommandCT.ThrowIfCancellationRequested();
                }
                catch (OperationCanceledException CancelEx)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @" Work Canceled. [SystemX.Net.XAdaptor.PC.XPCAdaptor : RecvProcessTask.WatchRecvCommandQueue]\r\n" + CancelEx.Message, 
                        ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                    break;
                }
                //
                try
                {
                    if (StateClientSocketConnect == false)
                        continue;

                    if (thisConnInfo.stCommandCheckTime.ElapsedMilliseconds >= 60000)
                    {
                        await SendCommandConnectState().ConfigureAwait(false);

                        thisConnInfo.OnCommandCheckTime();
                    }

                    if (bTaskCommandWaitLock == false)
                    {
                        bool bResult = QueryRecvCommandQueue();
                    }
                }
                catch (Exception ex)
                {
                    //throw new CommonScheduleException("General Queue Process failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : RecvProcessTask.WatchRecvQueue]");
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"General Queue Process failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : RecvProcessTask.WatchRecvCommandQueue]\r\n" + ex.Message, 
                        ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }
            }
        }

        private bool CommandQueueCheck()
        {
            if (ClientCommandSock == null)
                return false;

            if (ClientCommandSock != null)
            {
                if (ClientCommandSock.CONNECT == false)
                    return false;
            }

            if (FlowCommandControl == null)
                return false;

            //Login 타임아웃
            if (thisConnInfo.bHostLoginState == false)
            {
                if (thisConnInfo.stLoginTimeOut.ElapsedMilliseconds >= LOGIN_TIMEOUT)
                {
                    AdaptorAbort(true);

                    return false;
                }
            }

            return true;
        }

        private bool QueryRecvCommandQueue()
        {
            bool bState = true;

            try
            {
                if (CommandQueueCheck() == false)
                    return false;

                bTaskCommandWaitLock = true;

                if (FlowCommandControl.GetCurrentRecvProcessData() != null)
                    return false;

                thisConnInfo.m_iSendCommandQueueSize = FlowCommandControl.GetSendQueueSize();
                thisConnInfo.m_iRecvCommandQueueSize = FlowCommandControl.GetRecvQueueSize();

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

                XData getXData = FlowCommandControl.GetResultPacketData();

                if (getXData == null)
                    return false;

                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;

                thisConnInfo.OnCommandCheckTime();

                switch (CODE)
                {
                    case BASE_PROTOCOL.PROTOCOL_CODE.CONNECT_STATE:
                        {
                            PING_PACKET GetPingPacket = (PING_PACKET)objData;

                            string strGetMsg = GetPingPacket.objCheckMsg[0].Data;

                            strCheckCommandMsg = strGetMsg;

                            if (strCheckCommandMsg.IndexOf("TLRL") >= 0)
                            {
                                string[] getStationCheck = strCheckCommandMsg.Split(';');

                                if (getStationCheck.Length >= 2)
                                {
                                    int nGetStaionID = Convert.ToInt32(getStationCheck[1]);

                                    if (dicTestListNeedReload.ContainsKey(nGetStaionID))
                                    {
                                        if (dicTestListNeedReload[nGetStaionID] == false)
                                            dicTestListNeedReload[nGetStaionID] = true;
                                    }
                                    else
                                        dicTestListNeedReload.Add(nGetStaionID, true);
                                }
                            }
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.DATASET_TRANSEFER:
                        {
                            /*bQueryResult = getXData.bReplayResult;

                            if (bQueryResult)
                            {
                                //Query 문 실행 성공
                                QueryDataSet = objData as DataSet;
                            }
                            else
                            {
                                //Query 문 실행 실패(구문 오류 또는 연결 오류)
                                QueryDataSet = null;
                            }*/
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.HOST_INFO_CHECK:
                        {
                            thisConnInfo.stLoginTimeOut.Restart();
                            thisConnInfo.bHostLoginState = false;

                            SYSTEM_HOST_PACKET usPacket = (SYSTEM_HOST_PACKET)objData;

                            string strGetHostID = usPacket.objHostID[0].Data;
                            string strGetSection = usPacket.objSection[0].Data;
                            string strGetTestCode = usPacket.objTestCode[0].Data;
                            string strGetMessage = usPacket.objMessage[0].Data;

                            if (strGetMessage.IndexOf("[SUCCESS]") >= 0)
                            {
                                thisConnInfo.bHostLoginState = true;

                                SubscribeConnectInfo.bSubscriberClientResult = true;
                                
                                if (SubscribeConnectInfo.bUIMUseMode)
                                {
                                    SubscribeConnectInfo.SessionTimeSet();

                                    SubscribeConnectInfo.bSessionStarted = true;
                                }
                            }

                            AdaptorInformation.LOGIN_RESULT = thisConnInfo.bHostLoginState;
                            AdaptorInformation.LOGIN_MESSAGE = strGetMessage;

                            OnLoginAlarm(null, null);

                            if (thisConnInfo.bHostLoginState)
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Middleware login reply infomation : " + strGetMessage, ConsoleColor.Green, LogMessageLevel.DEBUG);
                            else
                            {
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"The middleware connection will be closed after " + (LOGIN_TIMEOUT / 1000).ToString() + " seconds. ", ConsoleColor.Red, LogMessageLevel.DEBUG);
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Middleware login reply infomation : " + strGetMessage, ConsoleColor.Red, LogMessageLevel.DEBUG);
                            }
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.SYSTEM_QUERY:
                        {
                            QUERY_PACKET usPacket = (QUERY_PACKET)objData;

                            string strGetQuery = usPacket.objQueryText[0].Data;
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.USER_QUERY:
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.RAW_SIZE:
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.ETC:
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.INITILALIZE_INFO:
                        {
                            GetConnectionInfo = (COMM_INFO_PACKET)objData;

                            StateClientGetInformation = true;

							if (ConnectStartStyleAuto == false)
                            {
                                //if (getXData.nLabel == PacketFlowControl.CommInfoManualToken)
                                //    break;
                                if (GetConnectionInfo.objConnLocalAddress[0].Data.CompareTo("AUTO") == 0)
                                    break;
                            }

                            //ConnectionInfoRecvEvent?.BeginInvoke(null, null, null, null);
                            //ConnectionInfoRecvEvent?.Invoke(null, null);

                            if (GetConnectionInfo.bPortDistribution == false)
                            {
                                OnConnectionInfoRecv(null, null);

                                thisConnInfo.InitialInfoState = true;
                            }

                            SubscribeConnectInfo.Initialize();

                            if (GetConnectionInfo.bPortDistribution)
                            {
                                SubscribeConnectInfo.nChangeCommandPort = GetConnectionInfo.usPortCommandNumber;
                                SubscribeConnectInfo.nChangeStreamPort = GetConnectionInfo.usPortStreamNumber;

                                AdaptorAbort();

                                SubscribeConnectInfo.bReqConnectAbort = false;
                                SubscribeConnectInfo.bSetChangeConnect = true;
                            }
                            else
                            {
                                string strSetInfoID = string.Empty;
                                string strSetInfoKey = string.Empty;
                                string strSetInfoTestCode = string.Empty;

                                if (LoginID.Length > 0)
                                {
                                    //UIM 모드 : 사용자 프로그램(Session 존재)
                                    SubscribeConnectInfo.bUIMUseMode = true;

                                    strSetInfoID = LoginID;
                                    strSetInfoKey = LoginKEY;

                                    strSetInfoTestCode = "";
                                }
                                else
                                {
                                    strSetInfoID = LoadInfo.HOST_ID;
                                    strSetInfoKey = LoadInfo.SECTION;

                                    strSetInfoTestCode = LoadInfo.TEST_CODE;
                                }

                                if (Login(strSetInfoID, strSetInfoKey, strSetInfoTestCode,
                                    SubscribeConnectInfo.bUIMUseMode, LoadInfo.SIMPLE_LOOKUP_OPTION) == false)
                                {
                                    AdaptorAbort();

                                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"SystemX.Net.XAdaptor.PC Login Unknown Error. [SystemX.Net.PCAdaptor : XPCAdaptor.QueryRecvCommandQueue]", ConsoleColor.Red, LogMessageLevel.DEBUG);
                                }
                            }
                        }
                        break;
                }

                thisConnInfo.OffCommandTime();

                RecvWaitEvent?.BeginInvoke(waitCommandParam, null, new AsyncCallback(RecvWaitEnd), null);
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" General Queue Process <Command> failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : RecvProcessTask.QueryRecvCommandQueue]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                bState = false;
            }
            finally
            {
                bTaskCommandWaitLock = false;
            }

            return bState;
        }
    }
}
