using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SystemX.Common;
using SystemX.Common.Archive;
using SystemX.Net.BaseProtocol;
using SystemX.Net.Schedule;
using static SystemX.Net.Platform.Common.Util.LogMessage;

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

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

                if (FlowStreamControl == null)
                    return;

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

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

                if (FlowStreamControl == null)
                    return;

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

                //소켓 리시브 행위 결과 전송
                if (e.PROCESS_RESULT == false)
                {
                    //받기 실패 단순 실패 응답
                    FlowStreamControl.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))
                            FlowStreamControl.SetSendPacketDrop();
                        else
                            FlowStreamControl.SendPacketCycle();

                        thisConnInfo.OffStreamTime();
                    }
                    //파일 끝 응답
                    else if (GET_CODE == BASE_PROTOCOL.PROTOCOL_CODE.RAW_END)
                    {
                        if (XCommons.GetSimpleResponsResult(iStoreCnt, recvStoreBuffer))
                            FlowStreamControl.RawStoreQueuePOP();
                        else
                            FlowStreamControl.RawStoreQueuePOP();

                        thisConnInfo.OffStreamTime();
                    }
                    //일반 응답
                    else
                    {
                        //성공 응답 
                        FlowStreamControl.InsertSendQueue(DateTime.Now, XCommons.SetSimpleResponsPacket(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.SIMPLE_RESPONSE), true), null, false, false);

                        //받은 큐에 넣어놓기
                        FlowStreamControl.InsertRecvQueue(senderData, null, e.nLABEL);

                        thisConnInfo.OffStreamTime();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"General <RecvStreamEvent> failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : RecvStreamEvent]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
        }
        private async void WatchRecvStreamQueue()
        {
            await Task.Delay(500).ConfigureAwait(false);

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

            thisConnInfo.OnStreamTime();
            thisConnInfo.OnStreamCheckTime();

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

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

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

                    if (thisConnInfo.stStreamCheckTime.ElapsedMilliseconds >= 60000)
                    {
                        await SendStreamConnectState().ConfigureAwait(false);

                        thisConnInfo.OnStreamCheckTime();
                    }

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

            //return true;
        }

        private bool StreamQueueCheck()
        {
            if (ClientStreamSock == null)
                return false;

            if (ClientStreamSock != null)
            {
                if (ClientStreamSock.CONNECT == false)
                    return false;
            }
            //
            if (FlowStreamControl == null)
                return false;

            return true;
        }

        private bool QueryRecvStreamQueue()
        {
            bool bState = true;

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

                bTaskStreamWaitLock = true;
                //
                if (FlowStreamControl.GetCurrentRecvProcessData() != null)
                    return false;

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

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

                XData getXData = FlowStreamControl.GetResultPacketData();

                if (getXData == null)
                    return false;

                thisConnInfo.stStreamProcessTime.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;

                thisConnInfo.OnStreamCheckTime();

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

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

                            strCheckStreamMsg = strGetMsg;

                            RecvWaitEvent?.BeginInvoke(waitStreamParam, null, new AsyncCallback(RecvWaitEnd), null);
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.SYNC_TIME_SERVER:
                        {
                            TIME_PACKET GetTimePacket = (TIME_PACKET)objData;

                            string strGetMsg = GetTimePacket.objMsg[0].Data;

                            RecvWaitEvent?.BeginInvoke(waitStreamParam, null, new AsyncCallback(RecvWaitEnd), null);
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.MIDDLEWARE_MESSAGE:
                        {
                            MESSAGE_PACKET GetMessagePacket = (MESSAGE_PACKET)objData;

                            string strGetMsg = GetMessagePacket.objMessage[0].Data;

                            GetMiddlewareMessage = strGetMsg;
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.FILE_TRANSFER:
                        {
                            byte[] ucFileData = objData as byte[];
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.TRANSFER_RESULT:
                        {
                            RecvWaitEvent?.BeginInvoke(waitStreamParam, null, new AsyncCallback(RecvWaitEnd), null);
                        }
                        break;
                    case BASE_PROTOCOL.PROTOCOL_CODE.RAW_SIZE:
                        {
                            if (getHeader.uiSourDataNum > 1)
                            {
                                if (thisConnInfo.nFileRecvPos > 0)
                                {
                                    if ((thisConnInfo.nFileRecvPos + 1) != getHeader.uiSourDataNum ||
                                       thisConnInfo.nFileRecvEndPos == 0)
                                    {
                                        thisConnInfo.nFileRecvPos = 0;
                                        thisConnInfo.nFileRecvEndPos = 0;

                                        FlowStreamControl.InsertSendQueue(DateTime.Now, XCommons.SetSimpleResponsPacket(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.RAW_END), false), null, false, false);

                                        break;
                                    }
                                }
                            }
                            //
                            if (getHeader.uiSourDataNum == 1)
                            {
                                thisConnInfo.lstRecvFileBytes = new List<Tuple<int, byte[]>>();
                                thisConnInfo.lstRecvFileBytes.Clear();

                                thisConnInfo.lstRecvFileBytes.Add(new Tuple<int, byte[]>((int)getHeader.uiSourDataNum, objData as byte[]));

                                thisConnInfo.nFileRecvPos = (int)getHeader.uiSourDataNum;
                                thisConnInfo.nFileRecvEndPos = (int)getHeader.uiDestDataNum;

                                thisConnInfo.strRecvFileName = getHeader.objOptionName[0].Data;
                                thisConnInfo.strRecvExtension = getHeader.objOptionExtension[0].Data;
                            }
                            else
                            {
                                thisConnInfo.lstRecvFileBytes.Add(new Tuple<int, byte[]>((int)getHeader.uiSourDataNum, objData as byte[]));

                                thisConnInfo.nFileRecvPos++;
                            }
                            //
                            if (thisConnInfo.nFileRecvPos >= thisConnInfo.nFileRecvEndPos)
                            {
                                int iSize = 0;

                                foreach (Tuple<int, byte[]> tData in thisConnInfo.lstRecvFileBytes)
                                    iSize += tData.Item2.Count();

                                byte[] ucGetDatas = new byte[iSize];

                                int iCopyPos = 0;

                                foreach (Tuple<int, byte[]> tData in thisConnInfo.lstRecvFileBytes)
                                {
                                    Array.Copy(tData.Item2, 0, ucGetDatas, iCopyPos, tData.Item2.Count());

                                    iCopyPos += tData.Item2.Count();
                                }

                                if (getHeader.usPalletIndex == ushort.MaxValue)
                                {
                                    string strGetTestListCntID = getHeader.objVarParam1[0].Data;

                                    QueryTestListProcess(ucGetDatas, strGetTestListCntID);

                                    //Task<int> tkProcTestlist = new Task<int>(new Func<int>(() => QueryTestListProcess(ucGetDatas).Result));
                                    //tkProcTestlist.Start();

                                    //PacketFlowControl.TestListResultToken
                                    if (FlowStreamControl.STM.GetLabel(getXData.nLabel) == getXData.nLabel)
                                    {
                                        FlowStreamControl.STM.SetLabel(getXData.nLabel, getXData);

                                        RecvWaitEvent?.BeginInvoke(waitStreamParam, null, new AsyncCallback(RecvWaitEnd), null);
                                    }
                                }

                                thisConnInfo.nFileRecvPos = 0;
                                thisConnInfo.nFileRecvEndPos = 0;

                                FlowStreamControl.InsertSendQueue(DateTime.Now, XCommons.SetSimpleResponsPacket(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.RAW_END), true), null, false, false);
                            }
                        }
                        break;
                }

                thisConnInfo.lStreamTime = thisConnInfo.stStreamProcessTime.ElapsedMilliseconds;
            }
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" General Queue Process <Stream> failed.[SystemX.Net.XAdaptor.PC.XPCAdaptor : PCAdaptor.QueryRecvStreamQueue]\r\n" + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                bState = false;
            }
            finally
            {
                bTaskStreamWaitLock = false;
            }

            return bState;
        }
    }
}
