using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
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.Serialization;
using SystemX.Net.BaseProtocol;
using SystemX.Net.Comm;
using SystemX.Net.Comm.IIS_FTP;
using SystemX.Net.Schedule;

using static SystemX.Net.Platform.Common.Util.LogMessage;

namespace SystemX.Net.XAdaptor
{
    public class XAdaptorSystem
    {
        public string LoginID { set; protected get; }
        public string LoginKEY { set; protected get; }

        [ComVisible(true)]
        public bool StateClientSocketConnect { internal set; get; }

        [ComVisible(true)]
        public bool StateClientStreamSocketConnect { internal set; get; }

        [ComVisible(true)]
        public bool StateClientGetInformation { internal set; get; }

        [ComVisible(true)]
        public bool StateAdaptorConnect { internal set; get; }

        //
        protected ClientConnInfo AdaptorInformation;

        //private static object objFailedFileWriteLock = new object();

        private static object objLogWriteLock = new object();

        public bool ServerTestListLoadState;

        public ClientConnInfo AdaptorInfor()
        {
            return AdaptorInformation;
        }

        public string GetAdaptorConnectIP()
        {
            return AdaptorInformation.CONNECT_IP;
        }

        public string GetAdaptorHostID()
        {
            return AdaptorInformation.HOST_ID;
        }

        public string GetAdaptorSection()
        {
            return AdaptorInformation.SECTION;
        }

        public string GetAdaptorTestCode()
        {
            return AdaptorInformation.TEST_CODE;
        }

        public int GetAdaptorCommandPort()
        {
            return AdaptorInformation.COMMAND_PORT;
        }

        public int GetAdaptorStreamPort()
        {
            return AdaptorInformation.STREAM_PORT;
        }

        public bool GetAdaptorLoginResult()
        {
            return AdaptorInformation.LOGIN_RESULT;
        }

        public string GetAdaptorLoginMessage()
        {
            return AdaptorInformation.LOGIN_MESSAGE;
        }

        public long GetLastCommandTime()
        {
            return thisConnInfo.lCommandTime;
        }

        public long GetLastStreamTime()
        {
            return thisConnInfo.lStreamTime;
        }

        public int[] GetReloadNeedStation()
        {
            return dicTestListNeedReload.Keys.ToArray();
        }

        public bool GetStateReloadNeedTestList(int nStationID)
        {
            if (dicTestListNeedReload.ContainsKey(nStationID))
                return dicTestListNeedReload[nStationID];
            else
                return false;
        }

        public void SetStateReloadNeedTestList(int nStationID)
        {
            if (dicTestListNeedReload.ContainsKey(nStationID))
                dicTestListNeedReload[nStationID] = false;
        }

        protected Dictionary<int, bool> dicTestListNeedReload = new Dictionary<int, bool>();

        public COMM_INFO_PACKET GetConnectionInfo { protected set; get; }

        public SubscriberClient SubscribeConnectInfo { protected set; get; }

        protected bool ClientReadyEndPoint { set; get; }

        protected ClientInfo LoadInfo;

        public string REF_CONNECT_IP { protected set; get; }
        public bool ConnectStartStyleAuto { set; get; } = true;

        //설정 파일과 별개로 IP를 변경해서 접속할때(for UIM)
        public void SetAdaptorConnectIP(string strSetIP)
        {
            string[] strGetSplitText = strSetIP.Split(',');

            if (strGetSplitText.Length == 2)
            {
                string strGetIP = strGetSplitText[0];
                string strGetPort = strGetSplitText[1];

                REF_CONNECT_IP = strGetIP;
            }
            else
                REF_CONNECT_IP = strSetIP;
        }

        public double? GetIssueWorkerWaitTime()
        {
            return LoadInfo?.ISSUE_WORKER_WAIT_TIME_ms;
        }

        public double? GetSessionTimeoutTime()
        {
            return LoadInfo?.SESSION_TIMEOUT_TIME_S;
        }


        public event EventHandler CommandConnectAlarmEvent;
        public event EventHandler StreamConnectAlarmEvent;

        public event EventHandler ConnectionInfoRecvEvent;

        public event EventHandler CommandDisconnectAlarmEvent;
        public event EventHandler StreamDisconnectAlarmEvent;

        public event EventHandler LoginAlarmEvent;

        public event EventHandler QueryCallEvent;

        public XAdaptorSystem()
        {
            SubscribeConnectInfo = new SubscriberClient();

            REF_CONNECT_IP = string.Empty;

            LoginID = string.Empty;
            LoginKEY = string.Empty;

            ServerTestListLoadState = false;
        }

        // TODO : FTP ALIS
        public eFTPServiceStatus StateFTP { set; get; } = eFTPServiceStatus.None;

        protected CtrlFTP ControlFTP;

        protected void XAdaptorLogWrite(string strWriteMsg)
        {
            string strYYYY = DateTime.Today.ToString("yyyy");
            string strMM = DateTime.Today.ToString("MM");
            string strdd = DateTime.Today.ToString("dd");

            string strHHmmssfff = DateTime.Today.ToString("HHmmssfff");

            string strFileSubName = string.Empty;

            try
            {
                strFileSubName = AdaptorInformation.HOST_ID + "_" + AdaptorInformation.SECTION;
            }
            catch
            {
                strFileSubName = string.Empty;
            }

            string strGetRoot = Path.GetPathRoot(Environment.CurrentDirectory);

            string DirPath = strGetRoot + $@"\XLog\Log\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strdd}\";

            string FilePath = string.Empty;

            if (strFileSubName.Length > 0)
                FilePath = DirPath + @"\XLog_" + DateTime.Today.ToString("yyyyMMdd") + "_" + strFileSubName + ".Xlog";
            else
                FilePath = DirPath + @"\XLog_" + DateTime.Today.ToString("yyyyMMdd") + ".Xlog";

            string temp;

            lock (objLogWriteLock)
            {
                DirectoryInfo di = new DirectoryInfo(DirPath);
                FileInfo fi = new FileInfo(FilePath);

                try
                {
                    if (!di.Exists) Directory.CreateDirectory(DirPath);
                    if (!fi.Exists)
                    {
                        using (StreamWriter sw = new StreamWriter(FilePath))
                        {
                            temp = string.Format("[{0}] : {1}", DateTime.Now, strWriteMsg);
                            sw.WriteLine(temp);
                            sw.Close();
                        }
                    }
                    else
                    {
                        using (StreamWriter sw = File.AppendText(FilePath))
                        {
                            temp = string.Format("[{0}] : {1}", DateTime.Now, strWriteMsg);
                            sw.WriteLine(temp);
                            sw.Close();
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message.ToString());
                    Console.WriteLine(e.StackTrace.ToString());
                }
            }
        }

        protected void XAdaptorFileLogWrite(eSetFileLogCategory SetCategory, string strYYYY, string strMM, string strDD, string strGetLogHeader, string strGetFileName, string strMsg)
        {
            string strWriteMsg = "{" + strGetLogHeader + "}{" + strGetFileName + "} - " + strMsg;

            string strFileSubName = string.Empty;

            try
            {
                strFileSubName = AdaptorInformation.HOST_ID + "_" + AdaptorInformation.SECTION;
            }
            catch
            {
                strFileSubName = string.Empty;
            }

            string strGetRoot = Path.GetPathRoot(Environment.CurrentDirectory);

            string DirPath = string.Empty;

            string LogFilePath = string.Empty;

            if (SetCategory == eSetFileLogCategory.FileLog)
            {
                DirPath = strGetRoot + $@"\XLog\FileFailedBackup\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strDD}\";

                if (strFileSubName.Length > 0)
                    LogFilePath = DirPath + @"\XLog_FailedCpLog_" + strYYYY + strMM + strDD + "_" + strFileSubName + ".Xlog";
                else
                    LogFilePath = DirPath + @"\XLog_FailedCpLog_" + strYYYY + strMM + strDD + ".Xlog";
            }
            else if (SetCategory == eSetFileLogCategory.FTPFileLog)
            {
                DirPath = @strGetRoot + $@"XLog\FTP\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strDD}\";

                if (strFileSubName.Length > 0)
                    LogFilePath = DirPath + @"\XLog_FTPCpLog_" + strYYYY + strMM + strDD + "_" + strFileSubName + ".Xlog";
                else
                    LogFilePath = DirPath + @"\XLog_FTPCpLog_" + strYYYY + strMM + strDD + ".Xlog";
            }

            string temp;

            lock (objLogWriteLock)
            {
                DirectoryInfo di1 = new DirectoryInfo(DirPath);
                if (!di1.Exists) Directory.CreateDirectory(DirPath);
                
                try
                {
                    FileInfo fi = new FileInfo(LogFilePath);

                    // 로그 쓰기            
                    if (!fi.Exists)
                    {
                        using (StreamWriter sw = new StreamWriter(LogFilePath))
                        {
                            temp = string.Format("[{0}] : {1}", DateTime.Now, strWriteMsg);
                            sw.WriteLine(temp);
                            sw.Close();
                        }
                    }
                    else
                    {
                        using (StreamWriter sw = File.AppendText(LogFilePath))
                        {
                            temp = string.Format("[{0}] : {1}", DateTime.Now, strWriteMsg);
                            sw.WriteLine(temp);
                            sw.Close();
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message.ToString());
                    Console.WriteLine(e.StackTrace.ToString());
                }
            }
        }

        protected string MakeZipIncludeInfoCpLog(string strGetLogHeader, string strGetFilePos, string strGetFileName, byte[] ucGetFileData)
        {
            string strWriteMsg = "{" + strGetLogHeader + "}{" + strGetFileName + "}";

            string strYYYY = DateTime.Today.ToString("yyyy");
            string strMM = DateTime.Today.ToString("MM");
            string strdd = DateTime.Today.ToString("dd");

            string strHHmmssfff = DateTime.Now.ToString("HHmmssfff");

            string strGetRoot = Path.GetPathRoot(Environment.CurrentDirectory);

            string DirPath = @strGetRoot + $@"XLog\FTP\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strdd}\";
            string CpLogDirPath = @strGetRoot + $@"XLog\FTP\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strdd}\{strHHmmssfff}\";

            string HeaderFilePath = string.Empty;
            string CpLogFilePath = string.Empty;

            string CpLogFileCompressPath = string.Empty;

            HeaderFilePath = @CpLogDirPath + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ";" + strGetLogHeader + ".txt";
            CpLogFilePath = @CpLogDirPath + strGetFileName;

            CpLogFileCompressPath = @DirPath + @"\" + ";" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ";" + strGetLogHeader + ";0;.zip";

            DirectoryInfo di1 = new DirectoryInfo(@DirPath);
            if (!di1.Exists) Directory.CreateDirectory(@DirPath);

            DirectoryInfo di2 = new DirectoryInfo(@CpLogDirPath);
            if (!di2.Exists) Directory.CreateDirectory(@CpLogDirPath);

            try
            {
                FileInfo fi1 = new FileInfo(strGetFilePos);

                //정보 파일 생성
                using (StreamWriter sw = new StreamWriter(HeaderFilePath, false))
                {
                    //Create File
                }

                FileInfo fi = new FileInfo(HeaderFilePath);
                fi.IsReadOnly = false;

                //기존 전달받은 경로에 파일 존재 할 경우 해당 파일 복사
                if (fi1.Exists)
                {
                    // 원본 파일 위치
                    var sourceCpLogFile = strGetFilePos;

                    // 파일 이동할 곳 
                    var destCpLogFile = CpLogFilePath;

                    // 1. 압축할 폴더로 데이터 복사 
                    System.IO.File.Copy(sourceCpLogFile, destCpLogFile, true);

                    fi = new FileInfo(destCpLogFile);
                    fi.IsReadOnly = false;
                }
                else
                {
                    if (ucGetFileData == null)
                    {
                        throw new Exception("File info error.");
                    }
                    else
                    {
                        using (FileStream file = new FileStream(CpLogFilePath, FileMode.Create))
                        {
                            file.Write(ucGetFileData, 0, ucGetFileData.Length);
                            file.Close();
                        }

                        fi = new FileInfo(CpLogFilePath);
                        fi.IsReadOnly = false;
                    }
                }

                // 특정 폴더, .zip으로 압축 
                ZipFile.CreateFromDirectory(CpLogDirPath, CpLogFileCompressPath);

                // 압축 끝난 폴더 삭제
                System.IO.Directory.Delete(CpLogDirPath, true);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message.ToString());
                Console.WriteLine(e.StackTrace.ToString());

                strWriteMsg += e.Message;

                Console.WriteLine(strWriteMsg);

                CpLogFileCompressPath = string.Empty;
            }

            return CpLogFileCompressPath;
        }

        protected void XAdaptorFailedFileBackupProc(eFileSendRecvResult eResult, string strGetLogHeader, string strGetFilePos, string strGetFileName, byte[] ucGetFileData)
        {
            string strWriteMsg = "{" + eResult.ToString() + "}{" + strGetLogHeader + "}{" + strGetFileName + "}";

            string strYYYY = DateTime.Today.ToString("yyyy");
            string strMM = DateTime.Today.ToString("MM");
            string strdd = DateTime.Today.ToString("dd");

            string strHHmmss = DateTime.Now.ToString("HHmmss");

            string strFileSubName = string.Empty;

            try
            {
                strFileSubName = AdaptorInformation.HOST_ID + "_" + AdaptorInformation.SECTION;
            }
            catch
            {
                strFileSubName = string.Empty;
            }

            string strGetRoot = Path.GetPathRoot(Environment.CurrentDirectory);

            string DirPath = @strGetRoot + $@"XLog\FileFailedBackup\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strdd}\";
            string CpLogDirPath = @strGetRoot + $@"XLog\FileFailedBackup\{LoadInfo.HOST_ID}\{LoadInfo.SECTION}\{strYYYY}\{strMM}\{strdd}\{strHHmmss}\";

            string LogFilePath = string.Empty;
            string HeaderFilePath = string.Empty;
            string CpLogFilePath = string.Empty;

            string CpLogFileCompressPath = string.Empty;

            if (strFileSubName.Length > 0)
                LogFilePath = @DirPath + @"\XLog_FailedCpLog_" + DateTime.Today.ToString("yyyyMMdd") + "_" + strFileSubName + ".Xlog";
            else
                LogFilePath = @DirPath + @"\XLog_FailedCpLog_" + DateTime.Today.ToString("yyyyMMdd") + ".Xlog";

            HeaderFilePath = @CpLogDirPath + DateTime.Now.ToString("yyyyMMddHHmmss") + ";" + strGetLogHeader + ".txt";
            CpLogFilePath = @CpLogDirPath + strGetFileName;

            CpLogFileCompressPath = @DirPath + @"\" + ";" + DateTime.Now.ToString("yyyyMMddHHmmss") + ";" + strGetLogHeader + ";0;.zip";

            string temp;

            lock (objLogWriteLock)
            {
                DirectoryInfo di1 = new DirectoryInfo(@DirPath);
                if (!di1.Exists) Directory.CreateDirectory(@DirPath);

                DirectoryInfo di2 = new DirectoryInfo(@CpLogDirPath);
                if (!di2.Exists) Directory.CreateDirectory(@CpLogDirPath);

                try
                {
                    FileInfo fi1 = new FileInfo(strGetFilePos);

                    //정보 파일 생성
                    using (StreamWriter sw = new StreamWriter(HeaderFilePath, false))
                    {
                        //Create File
                    }

                    //기존 전달받은 경로에 파일 존재 할 경우 해당 파일 복사
                    if (fi1.Exists)
                    {
                        // 원본 파일 위치
                        var sourceCpLogFile = strGetFilePos;

                        // 파일 이동할 곳 
                        var destCpLogFile = CpLogFilePath;

                        // 1. 압축할 폴더로 데이터 복사 
                        System.IO.File.Copy(sourceCpLogFile, destCpLogFile, true);
                    }
                    else
                    {
                        if (ucGetFileData == null)
                        {
                            throw new Exception("File info error.");
                        }
                        else
                        {
                            using (FileStream file = new FileStream(CpLogFilePath, FileMode.Create))
                            {
                                file.Write(ucGetFileData, 0, ucGetFileData.Length);
                                file.Close();
                            }
                        }
                    }

                    // 특정 폴더, .zip으로 압축 
                    ZipFile.CreateFromDirectory(CpLogDirPath, CpLogFileCompressPath);

                    // 압축 끝난 폴더 삭제
                    System.IO.Directory.Delete(CpLogDirPath, true);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message.ToString());
                    Console.WriteLine(e.StackTrace.ToString());

                    strWriteMsg += e.Message;
                }
                //
                try
                {
                    FileInfo fi2 = new FileInfo(LogFilePath);

                    // 1. 로그 쓰기            
                    if (!fi2.Exists)
                    {
                        using (StreamWriter sw = new StreamWriter(LogFilePath))
                        {
                            temp = string.Format("[{0}] : {1}", DateTime.Now, strWriteMsg);
                            sw.WriteLine(temp);
                            sw.Close();
                        }
                    }
                    else
                    {
                        using (StreamWriter sw = File.AppendText(LogFilePath))
                        {
                            temp = string.Format("[{0}] : {1}", DateTime.Now, strWriteMsg);
                            sw.WriteLine(temp);
                            sw.Close();
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message.ToString());
                    Console.WriteLine(e.StackTrace.ToString());
                }
            }
        }


        //The event-invoking method that derived classes can override.
        protected virtual void OnCommandConnectAlarm(object sender, EventArgs e)
        {
            // Safely raise the event for all subscribers
            CommandConnectAlarmEvent?.Invoke(sender, e);
        }
        protected virtual void OnStreamConnectAlarm(object sender, EventArgs e)
        {
            // Safely raise the event for all subscribers
            StreamConnectAlarmEvent?.Invoke(sender, e);
        }

        protected virtual void OnConnectionInfoRecv(object sender, EventArgs e)
        {
            // Safely raise the event for all subscribers
            ConnectionInfoRecvEvent?.Invoke(sender, e);
        }

        protected virtual void OnCommandDisconnectAlarm(object sender, EventArgs e)
        {
            // Safely raise the event for all subscribers
            CommandDisconnectAlarmEvent?.Invoke(sender, e);
        }
        protected virtual void OnStreamDisconnectAlarm(object sender, EventArgs e)
        {
            // Safely raise the event for all subscribers
            StreamDisconnectAlarmEvent?.Invoke(sender, e);
        }

        protected virtual void OnLoginAlarm(object sender, EventArgs e)
        {
            // Safely raise the event for all subscribers
            LoginAlarmEvent?.BeginInvoke(sender, e, null, null);
        }

        protected virtual void OnQueryCall(object sender, ResultEventArgs e)
        {
            // Safely raise the event for all subscribers
            QueryCallEvent?.Invoke(sender, e);
        }
        protected virtual void OnBeginQueryCall(object sender, ResultEventArgs e)
        {
            // Safely raise the event for all subscribers
            QueryCallEvent?.BeginInvoke(sender, e, null, null);
        }

        protected IControlTestListDataSet mgrPRODTestList { set; get; }

        public IControlTestListDataSet CurrentTestList()
        {
            return mgrPRODTestList;
        }

        protected IControlTestListDataSet CreateTestListMgr()
        {
            return new TProdTestListInfo();
        }

        public string GetMiddlewareMessage { protected set; get; }

        protected ClientInfoStore thisConnInfo;
    }
}

