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

using SystemX.Common.Protocol.SIA;

using static SystemX.Net.Platform.Common.Util.LogMessage;
using System.Threading;
using SystemX.Net.Middleware.Commons;
using SystemX.Net.Platform.SystemX.Common;
using CpTesterPlatform.CpLogUtil;

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

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

                    break;
                }
                //
                try
                {
                    if (MappedLogQueueData.Count > 0)
                    {
                        Tuple<string, int, HEADER_PACKET, byte[]> GetMappedLogData;

                        if (MappedLogQueueData.TryPeek(out GetMappedLogData))
                        {
                            if (SetMemoryMappedFile(GetMappedLogData.Item1, GetMappedLogData.Item2, GetMappedLogData.Item3, GetMappedLogData.Item4))
                            {
                                nMappedLogDataInOutFailedCnt = 0;

                                if (MappedLogQueueData.TryDequeue(out GetMappedLogData) == false)
                                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" Dequeue(PASS) failed. [SystemX.Net.MiddlewareUI : MainForm.WatchRecvStreamQueue]\r\n", ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                            }
                            else
                            {
                                if (nMappedLogDataInOutFailedCnt > 1)
                                {
                                    nMappedLogDataInOutFailedCnt = 0;

                                    if (MappedLogQueueData.TryDequeue(out GetMappedLogData) == false)
                                        MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @" Dequeue(FAIL) failed. [SystemX.Net.MiddlewareUI : MainForm.WatchRecvStreamQueue]\r\n", ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                                }

                                nMappedLogDataInOutFailedCnt++;

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

                if(bUseMapLogProcess)
                    await Task.Delay(100);
                else
                    await Task.Delay(10000);
            }
        }

        public bool SetMemoryMappedFile(string strType, int nPos, HEADER_PACKET getHeader, byte[] ucFileData)
        {
            bool bMapLogCreateResult = true;

            int nSetSize = int.MaxValue;

            byte[] ucSetLogArray = null;

            int nSetReadyPos = (nPos - PORT_DISTRIBUTION_NUM) * LogSharedMemory.nMaxStationSize;

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

            CpLogProcessInfo.strProcessDebugInfo = strProcessDebugInfo;

            try
            {
                using (InfoLogSharedMemory memInfoLog = new InfoLogSharedMemory(ParamterMapInfoLog))
                {
                    InfoLogMappedPacket InfoLogMapFile = new InfoLogMappedPacket();
                    nSetSize = Marshal.SizeOf(InfoLogMapFile);
                    ucSetLogArray = new byte[nSetSize];
                    InfoLogMapFile = (InfoLogMappedPacket)SystemXNetSerialization.RawDeSerialize(ucSetLogArray, InfoLogMapFile.GetType());

                    if (memInfoLog.CheckFile())
                    {
                        bool bFindInfoLogResult = false;

                        //로그 처리가 필요한 위치 조회
                        bool[] bGetStationReadyLog = memInfoLog.Get(out bFindInfoLogResult, nSetSize);

                        if (bFindInfoLogResult)
                            Array.Copy(bGetStationReadyLog, 0, InfoLogMapFile.bLogDataReady, 0, SharedMemory.nMaxInfoFullAccessSize);

                        using (LogSharedMemory memLog = new LogSharedMemory(ParamterMapLog))
                        {
                            LogMappedPacket LogMapFile = new LogMappedPacket();
                            nSetSize = Marshal.SizeOf(LogMapFile);
                            ucSetLogArray = new byte[nSetSize];
                            LogMapFile = (LogMappedPacket)SystemXNetSerialization.RawDeSerialize(ucSetLogArray, LogMapFile.GetType());

                            LogMapFile.bSectionUse = true;
                            LogMapFile.objLogType[0].Data = strType;
                            LogMapFile.bLogFileReadComplete = false;
                            LogMapFile.bLogFileProcessComplete = false;
                            LogMapFile.nNumber = nPos;
                            LogMapFile.bShowCpLogProcessTime = bShowCpLogProcessTime;
                            LogMapFile.nCommandPort = ConnPool[nPos].nUseCommandPort;
                            LogMapFile.nStreamPort = ConnPool[nPos].nUseStreamPort;
                            LogMapFile.objHost[0].Data = thisConnInfo[nPos].strConnectHostID;
                            LogMapFile.objSection[0].Data = thisConnInfo[nPos].strConnectSection;

                            bool bMakeTempTestListCntID = false;
                            string strGetStationNameChk = getHeader.objCP_Packet[0].objStationName[0].Data;
                            string strSetOrgStationName = string.Empty;

                            bool bHaveTestListID = false;
                            string strGetTransferTestListCntID = string.Empty;

                            if (strGetStationNameChk.IndexOf(";@#$%;TFL") >= 0)
                            {
                                bMakeTempTestListCntID = true;

                                strSetOrgStationName = strGetStationNameChk.Substring(0, strGetStationNameChk.IndexOf(";@#$%;TFL"));
                            }
                            else
                                strSetOrgStationName = strGetStationNameChk;

                            strGetTransferTestListCntID = getHeader.objVarParam1[0].Data;

                            if (strGetTransferTestListCntID.Split('@').Count() > 1)
                                bHaveTestListID = true;

                            LogMapFile.objStationName[0].Data = strSetOrgStationName;
                            LogMapFile.objOptionFileName[0].Data = getHeader.objOptionName[0].Data;
                            LogMapFile.objOptionFileExtension[0].Data = getHeader.objOptionExtension[0].Data;

                            LogMapFile.nStationID = 0;
                            LogMapFile.objProdPNo[0].Data = getHeader.objCP_Packet[0].objProdNo_P[0].Data;
                            LogMapFile.objProdCNo[0].Data = getHeader.objCP_Packet[0].objProdNo_C[0].Data;
                            LogMapFile.objTestType[0].Data = getHeader.objCP_Packet[0].objTestType[0].Data;
                            LogMapFile.objTestCode[0].Data = getHeader.objCP_Packet[0].objTestCode[0].Data;
                            LogMapFile.objVersion[0].Data = getHeader.objCP_Packet[0].objVersion[0].Data;
                            LogMapFile.objProdCode[0].Data = getHeader.objCP_Packet[0].objProdCode[0].Data;
                            LogMapFile.nTestListVariantNo = (int)getHeader.objCP_Packet[0].uiTestListNo;

                            bool bCheckResult = string.IsNullOrEmpty(thisConnInfo[nPos].strResultTestListCntID);
                            if (bCheckResult || bMakeTempTestListCntID)
                            {
                                string strSetTempTestListCntID = string.Empty;

                                if (bHaveTestListID == false)
                                    strSetTempTestListCntID = DateTime.Now.ToString("yyyyMMddHHmmssfff") + "@0";
                                else
                                    strSetTempTestListCntID = strGetTransferTestListCntID;

                                /// TODO : Failed Transfer File
                                /// Ver 0
                                /// 빈 아이디가 아닐 경우 현재 아이디 정보와 재전송 파일 정보 비교하여 동일할 경우 현재 아이디로 저장
                                /// > 추후 분류(검색)에 문제가 될경우 임시 아이디로 변경 해야 할수도 있다.
                                ///
                                /// Ver 1
                                /// 실패한 파일일때만 아이디 확인, 없으면 임시, 있으면 보낸 아이디로 저장
                                /*
                                if (bCheckResult == false)
                                {
                                    string strHostSectionInfo =
                                    thisConnInfo[nPos].strConnectHostID + ";" +
                                    thisConnInfo[nPos].strConnectSection;

                                    string strMakeCntID =
                                    getHeader.objCP_Packet[0].objProdNo_C[0].Data + ";" +
                                    getHeader.objCP_Packet[0].objTestType[0].Data + ";" +
                                    getHeader.objCP_Packet[0].objTestCode[0].Data + ";" +
                                    getHeader.objCP_Packet[0].objVersion[0].Data + ";" +
                                    getHeader.objCP_Packet[0].objProdCode[0].Data;// + ";" +
                                    //strFileName;

                                    //패킷의 정보로 Dic 검색 후 존재 한다면 생성하여 현재 아이디랑 비교후 일치한다면 현재 ID 사용
                                    if (dicQueryTestListCntID.ContainsKey(strHostSectionInfo))
                                    {
                                        if (dicQueryTestListCntID[strHostSectionInfo].ContainsKey(strMakeCntID))
                                        {
                                            string strGetCurTLCntID = dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].dtAccessTime.ToString("yyyyMMddHHmmssfff") + "@" +
                                            dicQueryTestListCntID[strHostSectionInfo][strMakeCntID].nCnt.ToString();

                                            if (thisConnInfo[nPos].strResultTestListCntID.CompareTo(strGetCurTLCntID) == 0)
                                                strSetTempTestListCntID = thisConnInfo[nPos].strResultTestListCntID;
                                        }
                                    }
                                }
                                */

                                LogMapFile.objResultTestListCntID[0].Data = strSetTempTestListCntID;
                            }
                            else
                                LogMapFile.objResultTestListCntID[0].Data = thisConnInfo[nPos].strResultTestListCntID;

                            ucFileData.CopyTo(LogMapFile.ucLogData, 0);

                            LogMapFile.nLogDataSize = ucFileData.Count();
                            //
                            string strRandFilePath = string.Empty;

                            byte[] ucGetFileData = null;
                            byte[] ucSetFileData = null;

                            try
                            {
                                ucGetFileData = new byte[LogMapFile.nLogDataSize];
                                Array.Copy(LogMapFile.ucLogData, 0, ucGetFileData, 0, LogMapFile.nLogDataSize);
                            }
                            catch (Exception e)
                            {
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - Create file data make failed. [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                                ucGetFileData = null;

                                bMapLogCreateResult = false;
                            }
                            //
                            try
                            {
                                string strRandName = Path.GetRandomFileName();
                                string strRandFile = Path.GetFileNameWithoutExtension(strRandName);

                                string strRandPath = Path.GetTempPath();
                                strRandFilePath = strRandPath + strRandFile + LogMapFile.objOptionFileExtension[0].Data;

                                if (ucGetFileData == null)
                                    throw new Exception("CpLog - Log file data null.");

                                if (LogMapFile.objLogType[0].Data == "RAW_SIZE")
                                    ucSetFileData = XDataArchive.DecompressGZipByteToByte(ucGetFileData);
                                else if (LogMapFile.objLogType[0].Data == "FILE_TRANSFER")
                                    ucSetFileData = XDataArchive.DecompressDeflateByteToByte(ucGetFileData);

                                if (ucSetFileData == null)
                                    throw new Exception("CpLog - Log file data decompress failed.");

                                CpLogHeader getCpLogHeader = null;

                                File.WriteAllBytes(strRandFilePath, ucSetFileData);

                                //해당 CpLog 파일 읽기 및 헤더 정보 획득
                                DataTable dtLogData = null;
                                dtLogData = CpLogFileIO.GetLogData(strRandFilePath, out getCpLogHeader);

                                if (dtLogData != null && getCpLogHeader != null)
                                {
                                    string strGetStationID = getCpLogHeader.CHANNEL.Trim();

                                    int nGetStationID = int.MaxValue;
                                    if (int.TryParse(strGetStationID, out nGetStationID))
                                        LogMapFile.nStationID = nGetStationID;

                                    if (nGetStationID < 0)
                                    {
                                        LogMapFile.nStationID = 0;

                                        MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - StationID negative value [" + nGetStationID.ToString() + "] detect. [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] ", ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                                    }
                                }

                                if (LogMapFile.nStationID >= LogSharedMemory.nMaxStationSize)
                                {
                                    if (InfoLogMapFile.bLogDataReady[nSetReadyPos])
                                        InfoLogMapFile.bLogDataReady[nSetReadyPos] = false;
                                    else
                                        InfoLogMapFile.bLogDataReady[nSetReadyPos] = true;
                                }
                                else
                                {
                                    if (InfoLogMapFile.bLogDataReady[nSetReadyPos + LogMapFile.nStationID])
                                        InfoLogMapFile.bLogDataReady[nSetReadyPos + LogMapFile.nStationID] = false;
                                    else
                                        InfoLogMapFile.bLogDataReady[nSetReadyPos + LogMapFile.nStationID] = true;
                                }
                            }
                            catch (Exception e)
                            {
                                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - Check StationID failed. [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                                bMapLogCreateResult = false;
                            }
                            finally
                            {
                                if (File.Exists(strRandFilePath))
                                    File.Delete(strRandFilePath);

                                if (bMapLogCreateResult == false)
                                {
                                    //문제 발생 로그 확인 파일생성 위치 및 파일명 생성
                                    if (ucGetFileData == null)
                                        goto CHECK_LOG_FILE_MAKE_SKIP;
                                    if (ucSetFileData == null)
                                        goto CHECK_LOG_FILE_MAKE_SKIP;

                                    try
                                    {
                                        string strMakeDate = DateTime.Now.ToString(@"yyyy\\MM\\dd\\");

                                        string strCreateFileName = CPXV2_GetCheckLogFilePath(LogMapFile, strMakeDate);

                                        if (File.Exists(strCreateFileName) == false)
                                            File.WriteAllBytes(strCreateFileName, ucSetFileData);
                                    }
                                    catch (Exception ex)
                                    {
                                        MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - Check log file create failed. [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                                    }
                                }

                                CHECK_LOG_FILE_MAKE_SKIP:;
                            }

                            memLog.Set(nPos, LogMapFile);
                        }

                        memInfoLog.Set(InfoLogMapFile);
                    }
                    else
                    {
                        if(memInfoLog.CheckExistsInfoFile() == false)
                            memInfoLog.Set(InfoLogMapFile);

                        //Info File Access Failed
                        bMapLogCreateResult = false;
                    }
                }
            }
            catch (Exception e)
            {
                /*
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - " + $"ST Frame Count {st.FrameCount} [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Red, LogMessageLevel.FATAL);

                for (int n = 0; n < st.FrameCount; n++)
                {
                    StackFrame sf = st.GetFrame(n);
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - " + $"ST Method To String {sf.GetMethod()} [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Red, LogMessageLevel.FATAL);
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - " + $"ST Method Name {sf.GetMethod().Name} [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Red, LogMessageLevel.FATAL);
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - " + $"ST Line Number {sf.GetFileLineNumber()} [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Red, LogMessageLevel.FATAL);
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - " + $"ST Column Number {sf.GetFileColumnNumber()} [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Red, LogMessageLevel.FATAL);
                }
                */
                
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + CpLogProcessInfo.strProcessDebugInfo + @" CpLog - Create Map Log failed. [SystemX.Net.MiddlewareUI : MainForm.SetMemoryMappedFile] " + e.Message, ConsoleColor.Red, LogMessageLevel.FATAL);

                bMapLogCreateResult = false;
            }

            //long l1 = stChkTime.ElapsedMilliseconds;

            return bMapLogCreateResult;
        }

        private string CPXV2_GetLogFileName(LogMappedPacket GetMappedInfo, string strCreateName)
        {
            Random randNumber = new Random();

            string strFileName = strCreateName;

            if (GetMappedInfo.objOptionFileName[0].Data.CompareTo("-") == 0)
                strFileName += @"LogFileTemp" + @randNumber.Next().ToString() + @GetMappedInfo.objOptionFileExtension[0].Data;
            else
                strFileName += @GetMappedInfo.objOptionFileName[0].Data + @GetMappedInfo.objOptionFileExtension[0].Data;

            if (File.Exists(strFileName) == true)
            {
                while (true)
                {
                    strFileName = strCreateName;

                    if (GetMappedInfo.objOptionFileName[0].Data.CompareTo("-") == 0)
                        strFileName += @"LogFileTemp" + @randNumber.Next().ToString() + @GetMappedInfo.objOptionFileExtension[0].Data;
                    else
                        strFileName += @GetMappedInfo.objOptionFileName[0].Data + "_" + @randNumber.Next().ToString() + @GetMappedInfo.objOptionFileExtension[0].Data;

                    if (File.Exists(strFileName) == false)
                        break;
                }
            }

            return strFileName;
        }

        private string CPXV2_GetCheckLogFilePath(LogMappedPacket GetMappedInfo,
            string strMakeDate,
            bool bGetOnlyFilePath = false)
        {
            string strMakeInfo = string.Empty;
            string strMakeName = string.Empty;

            strMakeInfo = LoadInfo.SERVER_SAVE_POS + @"\" + strMakeDate;
            strMakeInfo += @"LogFileSave_ProcessPort" + "(" + GetMappedInfo.nStreamPort + ")_" + GetMappedInfo.objHost[0].Data + "_" + GetMappedInfo.objSection[0].Data + @"\LogCheck\";

            if (Directory.Exists(strMakeInfo) == false)
                Directory.CreateDirectory(strMakeInfo);

            if (bGetOnlyFilePath == false)
                strMakeName = CPXV2_GetLogFileName(GetMappedInfo, strMakeInfo);
            else
                strMakeName = strMakeInfo;

            return strMakeName;
        }
    }
}
