using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SystemX.Common;
using SystemX.Common.Archive;
using SystemX.Common.Serialization;
using SystemX.Net.BaseProtocol;
using SystemX.Net.Comm;
using SystemX.Net.XAdaptor.PC.O2Sensor.NgCode;
using SystemX.Net.Schedule;
using SystemX.Net.XAdaptor;
using static SystemX.Net.Platform.Common.Util.LogMessage;
using WTimer = System.Windows.Forms.Timer;

namespace SystemX.Net.XAdaptor.PC
{
    public partial class XAdaptorPC
    {
        private bool QueryTestListProcess(byte[] ucGetDatas, string strGetTestListCntID)
        {
            bool bSetResult = false;

            try
            {
                DataSet QueryTestList = null;
                QueryTestList = XDataArchive.DecompressByteToDataset(ucGetDatas);

                (mgrPRODTestList as TProdTestListInfo).SetTestListDataSet(QueryTestList);
                (mgrPRODTestList as TProdTestListInfo).SetTestListCntID(strGetTestListCntID);

                if (XCommons.isHasRow(mgrPRODTestList.getTestListDataSet()))
                {
                    if (mgrPRODTestList.getTestListDataSet().Tables[0].Columns.Contains("TestListData"))
                    {
                        int iCol1 = mgrPRODTestList.getTestListDataSet().Tables[0].Columns.IndexOf("TestListData");
                        mgrPRODTestList.getTestListDataSet().Tables[0].Columns[iCol1].ColumnMapping = MappingType.Hidden;
                    }
                    if (mgrPRODTestList.getTestListDataSet().Tables[0].Columns.Contains("FileName"))
                    {
                        int iCol2 = mgrPRODTestList.getTestListDataSet().Tables[0].Columns.IndexOf("FileName");
                    }

                    bSetResult = true;
                }

                base.ServerTestListLoadState = true;

                //QueryCallEvent?.BeginInvoke(mgrPRODTestList.getTestListDataSet(), new ResultEventArgs(bSetResult), null, null);
                OnBeginQueryCall(mgrPRODTestList.getTestListDataSet(), new ResultEventArgs(bSetResult));
            }
            catch
            {
                bSetResult = false;
            }

            finally
            {
                ;//
            }

            return bSetResult;
        }

        /*
        private async void ClientCommandConnect()
        {
            dbNgCodeFinder = null;

            ConnectCommandWaitEvent.Reset();
            StateAdaptorConnect &= ClientCommandSet(SOCKET_TYPE.TCP, false);

            if (ConnectCommandWaitEvent.WaitOne(CONNECT_TIME_OUT))
                SetCommandWatchTask();
            else
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"SystemX.Net.XAdaptor.PC Command Connect Error.[SystemX.Net.PCAdaptor : XPCAdaptor.XPCAdaptor]", ConsoleColor.Red, LogMessageLevel.DEBUG);

            await Task.Delay(1).ConfigureAwait(false);
        }

        private async void ClientStreamConnect()
        {
            ConnectStreamWaitEvent.Reset();
            StateAdaptorConnect &= ClientStreamSet(SOCKET_TYPE.TCP, false);

            if (ConnectStreamWaitEvent.WaitOne(CONNECT_TIME_OUT))
                SetStreamWatchTask();
            else
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"SystemX.Net.XAdaptor.PC Stream Connect Error.[SystemX.Net.PCAdaptor : XPCAdaptor.XPCAdaptor]", ConsoleColor.Red, LogMessageLevel.DEBUG);

            await Task.Delay(1).ConfigureAwait(false);
        }
        */

        private void ClearCommandClientInstance()
        {
            if (FlowCommandControl != null)
            {
                FlowCommandControl.Dispose();
                FlowCommandControl = null;
            }

            if (ClientCommandSock != null)
            {
                ClientCommandSock.Comm_Connect_Event -= ClientCommandConnectEvent;
                ClientCommandSock.Socket_Error_Event -= ClientCommandErrorEvent;

                ClientCommandSock.Comm_Send_Event -= SendCommandEvent;
                ClientCommandSock.Comm_Recv_Event -= RecvCommandEvent;

                ClientCommandSock.Dispose();
                ClientCommandSock = null;
            }
        }

        private void ClearStreamClientInstance()
        {
            if (FlowStreamControl != null)
            {
                FlowStreamControl.Dispose();
                FlowStreamControl = null;
            }

            if (ClientStreamSock != null)
            {
                ClientStreamSock.Comm_Connect_Event -= ClientStreamConnectEvent;
                ClientStreamSock.Socket_Error_Event -= ClientStreamErrorEvent;

                ClientStreamSock.Comm_Send_Event -= SendStreamEvent;
                ClientStreamSock.Comm_Recv_Event -= RecvStreamEvent;

                ClientStreamSock.Dispose();
                ClientStreamSock = null;
            }
        }

        private IPAddress GetConnectIPAddress()
        {
            IPAddress setIP = null;

            if (LoadInfo.LOOP_BACK)
                setIP = IPAddress.Loopback;
            else
            {
                if (REF_CONNECT_IP.Length > 0)
                    setIP = IPAddress.Parse(REF_CONNECT_IP);
                else
                    setIP = IPAddress.Parse(LoadInfo.CONNECT_IP);
            }

            return setIP;
        }

        private int GetDistributionPort(Random r, int nStartPort)
        {
            //최대값 미만 + 1
            r.Next();
            return r.Next(nStartPort, nStartPort + 10);
        }

        private bool ClientCommandSet(SOCKET_TYPE SOCK_TYPE, bool bUseRandDistribution = true, int nSetPortNumber = int.MaxValue)
        {
            thisConnInfo.bHostLoginState = true;

            bool bClientStartState = true;
            //
            int nPortNumber = int.MaxValue;

            if (nSetPortNumber == int.MaxValue)
            {
                nPortNumber = LoadInfo.COMMAND_PORT;
            }
            else
                nPortNumber = nSetPortNumber;

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

                nPortNumber = GetDistributionPort(r, nPortNumber);
            }

            try
            {
                if (ClientReadyEndPoint == false)
                {
                    /*if (LoadInfo.LOOP_BACK)
                        ClientCommandEP = new IPEndPoint(IPAddress.Loopback, nPortNumber);
                    else
                        ClientCommandEP = new IPEndPoint(IPAddress.Parse(LoadInfo.CONNECT_IP), nPortNumber);*/

                    if (LoadInfo.LOOP_BACK)
                        ClientCommandEP = new IPEndPoint(GetConnectIPAddress(), nPortNumber);
                    else
                        ClientCommandEP = new IPEndPoint(GetConnectIPAddress(), nPortNumber);
                }

                ClearCommandClientInstance();

                //COMMAND
#if FALSE
                ClientCommandSock = new AsyncComClientSocket(ClientCommandEP);
#else
                ClientCommandSock = new AsyncClientSocket(SOCK_TYPE, ClientCommandEP);
#endif

                ClientCommandSock.Comm_Connect_Event += ClientCommandConnectEvent;
                ClientCommandSock.Socket_Error_Event += ClientCommandErrorEvent;

                ClientCommandSock.Comm_Send_Event += SendCommandEvent;
                ClientCommandSock.Comm_Recv_Event += RecvCommandEvent;

                FlowCommandControl = new PacketFlowControl(FlowControlType.Commnad, ClientCommandSock);

                ClientCommandSock.Connect();
            }
            catch (Exception ex)
            {
                bClientStartState = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client Command connect set failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : XPCAdaptor.ClientCommandSet()]\r\n" + ex.Message, ConsoleColor.Red, LogMessageLevel.DEBUG);
            }

            return bClientStartState;
        }

        private bool ClientStreamSet(SOCKET_TYPE SOCK_TYPE, bool bUseRandDistribution = true, int nSetPortNumber = int.MaxValue)
        {
            bool bClientStartState = true;

            int nPortNumber = int.MaxValue;

            if (nSetPortNumber == int.MaxValue)
                nPortNumber = LoadInfo.STREAM_PORT;
            else
                nPortNumber = nSetPortNumber;

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

                nPortNumber = GetDistributionPort(r, nPortNumber);
            }

            try
            {
                if (ClientReadyEndPoint == false)
                {
                    if (LoadInfo.LOOP_BACK)
                        ClientStreamEP = new IPEndPoint(GetConnectIPAddress(), nPortNumber);
                    else
                        ClientStreamEP = new IPEndPoint(GetConnectIPAddress(), nPortNumber);

                    /*if (LoadInfo.LOOP_BACK)
                        ClientStreamEP = new IPEndPoint(IPAddress.Loopback, nPortNumber);
                    else
                        ClientStreamEP = new IPEndPoint(IPAddress.Parse(LoadInfo.CONNECT_IP), nPortNumber);*/
                }

                ClearStreamClientInstance();

                //STREAM
#if FALSE
                ClientStreamSock = new AsyncComClientSocket(ClientStreamEP);
#else
                ClientStreamSock = new AsyncClientSocket(SOCK_TYPE, ClientStreamEP);
#endif

                ClientStreamSock.Comm_Connect_Event += ClientStreamConnectEvent;
                ClientStreamSock.Socket_Error_Event += ClientStreamErrorEvent;

                ClientStreamSock.Comm_Send_Event += SendStreamEvent;
                ClientStreamSock.Comm_Recv_Event += RecvStreamEvent;

                FlowStreamControl = new PacketFlowControl(FlowControlType.Stream, ClientStreamSock);

                ClientStreamSock.Connect();
            }
            catch (Exception ex)
            {
                bClientStartState = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Client Stream connect set failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : XPCAdaptor.ClientStreamSet()]\r\n" + ex.Message, ConsoleColor.Red, LogMessageLevel.DEBUG);
            }

            return bClientStartState;
        }

        private void ClearCommonVar()
        {
            SubscribeConnectInfo.bSessionStarted = false;
        }

        private void ClearCommandWatchTask()
        {
            CommandCTS.Cancel();

            if (taskRecvCommandProcess != null)
            {
                taskRecvCommandProcess.ContinueWith(t =>
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"taskRecvCommandProcess END. [SystemX.Net.XAdaptor.PC : XPCAdaptor.ClearWatchTask - Command]",
                        ConsoleColor.White,
                        LogMessageLevel.DEBUG); 
                });

                m_bTaskCommandBlock = true;

                taskRecvCommandProcess.ConfigureAwait(false);
                //taskRecvCommandProcess.Wait();

                taskRecvCommandProcess = null;
            }
        }

        private void ClearStreamWatchTask()
        {
            StreamCTS.Cancel();

            if (taskRecvStreamProcess != null)
            {
                taskRecvStreamProcess.ContinueWith(t =>
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"taskRecvStreamProcess END. [SystemX.Net.XAdaptor.PC : XPCAdaptor.ClearWatchTask - Stream]",
                        ConsoleColor.White,
                        LogMessageLevel.DEBUG);
                });

                m_bTaskStreamBlock = true;

                taskRecvStreamProcess.ConfigureAwait(false);
                //taskRecvStreamProcess.Wait();

                taskRecvStreamProcess = null;
            }
            //
            SubCTS.Cancel();

            if (taskSubProcess != null)
            {
                taskSubProcess.ContinueWith(t =>
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                        @"taskSubProcess END. [SystemX.Net.XAdaptor.PC : XPCAdaptor.ClearWatchTask - Stream(Sub)]",
                        ConsoleColor.White,
                        LogMessageLevel.DEBUG);
                });

                m_bTaskSubBlock = true;

                taskSubProcess.ConfigureAwait(false);
                //taskSubProcess.Wait();

                taskSubProcess = null;
            }
        }

        private void SetCommandWatchTask()
        {
            if (StateAdaptorConnect == false)
                return;

            ClearCommandWatchTask();

            taskRecvCommandProcess = null;
            m_bTaskCommandBlock = false;

            CommandCTS = new CancellationTokenSource();
            CommandCT = CommandCTS.Token;

            taskRecvCommandProcess = new Task(new Action(WatchRecvCommandQueue), CommandCT);
            taskRecvCommandProcess.Start();
        }

        private void SetStreamWatchTask()
        {
            if (StateAdaptorConnect == false)
                return;

            ClearStreamWatchTask();

            taskRecvStreamProcess = null;
            m_bTaskStreamBlock = false;

            StreamCTS = new CancellationTokenSource();
            StreamCT = StreamCTS.Token;

            taskRecvStreamProcess = new Task(new Action(WatchRecvStreamQueue), StreamCT);
            taskRecvStreamProcess.Start();
            //
            taskSubProcess = null;
            m_bTaskSubBlock = false;

            SubCTS = new CancellationTokenSource();
            SubCT = StreamCTS.Token;

            taskSubProcess = new Task(new Action(WatchSubProcess), SubCT);
            taskSubProcess.Start();
        }
    }
}

