using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
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.Schedule;
using static SystemX.Net.Platform.Common.Util.LogMessage;

namespace SystemX.Net.XAdaptor.PC
{
    [ComVisible(true)]
    [Guid("837C547C-E1EC-453E-BA98-2F5EEDFD6CF6")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("SystemX.Net.XAdaptor.PC.XAdaptorPC")]
    [ComDefaultInterface(typeof(IComXPCAdaptor))]
    public partial class XAdaptorPC
    {
        private string MakeDataSetToText(DataSet ds)
        {
            string strMakeText = string.Empty;
            string strMakeColInfo = "000@";
            string[] strRowTextArray = null;

            try
            {
                if (ds != null)
                {
                    foreach (DataTable dt in ds.Tables)
                    {
                        strRowTextArray = new string[dt.Rows.Count];

                        foreach (DataColumn dc in dt.Columns)
                            strMakeColInfo += dc.ColumnName + ",";

                        strMakeColInfo = strMakeColInfo.Remove(strMakeColInfo.Length - 1, 1);

                        strMakeColInfo += ";";

                        strMakeText = strMakeColInfo;

                        int iPos = 0;
                        foreach (DataRow dr in dt.Rows)
                        {
                            string[] strRowTrimArray = new string[dr.ItemArray.Count()];
                            for (int i = 0; i < dr.ItemArray.Count(); i++)
                                strRowTrimArray[i] = dr.ItemArray[i].ToString().Trim();

                            strRowTextArray[iPos] = string.Join(",", strRowTrimArray);
                            strRowTextArray[iPos] = strRowTextArray[iPos].Trim();

                            strMakeText += (iPos + 1).ToString("D3") + "@" + strRowTextArray[iPos] + ";";

                            iPos++;
                        }

                        break;
                    }
                }

                if (strRowTextArray == null)
                    strMakeText = "";
                else if (strRowTextArray.Count() <= 0)
                    strMakeText = "";
            }
            catch (Exception ex)
            {
                strMakeText = "";

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                    @"Dataset to text process fail. [SystemX.Net.XAdaptor.PC : XPCAdaptor.MakeDataSetToText]\r\n" +
                    ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return strMakeText;
        }

        [ComVisible(true)]
        public bool ComGetClientSocketConnect()
        {
            return StateClientSocketConnect;
        }

        [ComVisible(true)]
        public bool ComGetClientStreamSocketConnect()
        {
            return StateClientStreamSocketConnect;
        }

        [ComVisible(true)]
        public bool ComGetClientInfo()
        {
            return StateClientGetInformation;
        }

        [ComVisible(true)]
        public bool ComGetAdaptorConnectState()
        {
            return StateAdaptorConnect;
        }

        [ComVisible(true)]
        public string ComGetCommandMessage()
        {
            return strCheckCommandMsg;
        }

        [ComVisible(true)]
        public string ComGetStreamMessage()
        {
            return strCheckCommandMsg;
        }

        [ComVisible(true)]
        public async Task<bool> ComClientTryConnet(int nCommandPortNum = int.MaxValue, int nStreamPortNum = int.MaxValue)
        {
            bool bResult = true;

            StateAdaptorConnect = true;

            try
            {
                //ConnectCommandWaitEvent.Reset();
                //ConnectStreamWaitEvent.Reset();

                bConnectCommandSocketFlag = false;
                bConnectStreamSocketFlag = false;

                StateAdaptorConnect &= ClientCommandSet(SOCKET_TYPE.TCP, false, nCommandPortNum);
                StateAdaptorConnect &= ClientStreamSet(SOCKET_TYPE.TCP, false, nStreamPortNum);

                Stopwatch stWaitConnect = new Stopwatch();
                stWaitConnect.Start();

                while(stWaitConnect.ElapsedMilliseconds < CONNECT_TIME_OUT)
                {
                    if(bConnectCommandSocketFlag)
                    {
                        await Task.Delay(100).ConfigureAwait(false);

                        break;
                    }

                    await Task.Delay(10).ConfigureAwait(false);
                }
                if(bConnectCommandSocketFlag)
                    SetCommandWatchTask();
                else
                {
                    bResult = false;

                    throw new Exception("Can not connect Command Socket.");
                }
                //
                stWaitConnect.Restart();
                while (stWaitConnect.ElapsedMilliseconds < CONNECT_TIME_OUT)
                {
                    if (bConnectStreamSocketFlag)
                    {
                        await Task.Delay(100).ConfigureAwait(false);

                        break;
                    }

                    await Task.Delay(10).ConfigureAwait(false);
                }
                if (bConnectStreamSocketFlag)
                    SetStreamWatchTask();
                else
                {
                    bResult = false;

                    throw new Exception("Can not connect Stream Socket.");
                }
            }
            catch (Exception ex)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                    @"Client Connection Attempt Error. [SystemX.Net.XAdaptor.PC - IComXPCAdaptor : XPCAdaptor.ComClientTryConnet]\r\n" +
                    ex.Message, ConsoleColor.Red, LogMessageLevel.DEBUG);
            }
            finally
            {
                ;//
            }

            return bResult;
        }

        [ComVisible(true)]
        public async Task<bool> ComClientTryDistributionConnet(int nCommandPortNum = int.MaxValue)
        {
            bool bResult = true;

            StateAdaptorConnect = true;

            thisConnInfo.stLoginTimeOut.Restart();

            try
            {
                ClearCommandClientInstance();

                //ConnectCommandWaitEvent.Reset();

                bConnectCommandSocketFlag = false;

                StateAdaptorConnect &= ClientCommandSet(SOCKET_TYPE.TCP, true, nCommandPortNum);

                Stopwatch stWaitConnect = new Stopwatch();
                stWaitConnect.Start();

                while (stWaitConnect.ElapsedMilliseconds < CONNECT_TIME_OUT)
                {
                    if (bConnectCommandSocketFlag)
                    {
                        await Task.Delay(10).ConfigureAwait(false);

                        break;
                    }

                    await Task.Delay(10).ConfigureAwait(false);
                }
                if (bConnectCommandSocketFlag)
                    SetCommandWatchTask();
                else
                {
                    bResult = false;

                    throw new Exception("Can not connect Command Socket.");
                }
            }
            catch (Exception ex)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                    @"Client Connection Attempt Error. [SystemX.Net.XAdaptor.PC - IComXPCAdaptor : XPCAdaptor.ComClientTryConnet]\r\n" +
                    ex.Message, ConsoleColor.Red, LogMessageLevel.DEBUG);
            }
            finally
            {
                if (ClientCommandSock.SOCK_TYPE == SOCKET_TYPE.UDP && bResult)
                {
                    COMM_INFO_PACKET ConnectCommSendInfo = new COMM_INFO_PACKET();
                    int iSendSize = Marshal.SizeOf(ConnectCommSendInfo);
                    byte[] ucSendArray = new byte[iSendSize];
                    ConnectCommSendInfo = (COMM_INFO_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, ConnectCommSendInfo.GetType());

                    ConnectCommSendInfo.bPortDistribution = true;

                    ConnectCommSendInfo.usPortCommandNumber = (ushort)0;
                    ConnectCommSendInfo.usPortStreamNumber = (ushort)0;

                    ConnectCommSendInfo.objConnLocalAddress[0].Data = ClientCommandSock.strGetLocalAddress;
                    ConnectCommSendInfo.objConnLocalPort[0].Data = ClientCommandSock.strGetLocalPort;

                    byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.INITILALIZE_INFO), ConnectCommSendInfo);

                    FlowCommandControl.InsertSendQueue(DateTime.Now, ucSendByteInfo, null);
                }
            }

            return bResult;
        }

		[ComVisible(true)]
        public async Task<bool> WaitComClientTryDistributionConnet(int nCommandPortNum = int.MaxValue)
        {
            bool bResult = true;

            StateAdaptorConnect = true;

            thisConnInfo.stLoginTimeOut.Restart();

            try
            {
                ClearCommandClientInstance();

                //ConnectCommandWaitEvent.Reset();

                bConnectCommandSocketFlag = false;

                StateAdaptorConnect &= ClientCommandSet(SOCKET_TYPE.TCP, true, nCommandPortNum);

                Stopwatch stWaitConnect = new Stopwatch();
                stWaitConnect.Start();

                while (stWaitConnect.ElapsedMilliseconds < CONNECT_TIME_OUT)
                {
                    if (bConnectCommandSocketFlag)
                    {
                        await Task.Delay(10).ConfigureAwait(false);

                        break;
                    }

                    await Task.Delay(10).ConfigureAwait(false);
                }
                if (bConnectCommandSocketFlag)
                    SetCommandWatchTask();
                else
                {
                    bResult = false;

                    throw new Exception("Can not connect Command Socket.");
                }
            }
            catch (Exception ex)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                    @"Client Connection Attempt Error. [SystemX.Net.XAdaptor.PC - IComXPCAdaptor : XPCAdaptor.ComClientTryConnet]\r\n" +
                    ex.Message, ConsoleColor.Red, LogMessageLevel.DEBUG);
            }
            //
            finally
            {
                if (bResult)
                {
                    await Task.Delay(500).ConfigureAwait(false);

                    COMM_INFO_PACKET ConnectCommSendInfo = new COMM_INFO_PACKET();
                    int iSendSize = Marshal.SizeOf(ConnectCommSendInfo);
                    byte[] ucSendArray = new byte[iSendSize];
                    ConnectCommSendInfo = (COMM_INFO_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, ConnectCommSendInfo.GetType());

                    ConnectCommSendInfo.bPortDistribution = true;

                    ConnectCommSendInfo.usPortCommandNumber = (ushort)0;
                    ConnectCommSendInfo.usPortStreamNumber = (ushort)0;

                    byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.INITILALIZE_INFO), ConnectCommSendInfo);

                    FlowCommandControl.InsertSendQueue(DateTime.Now, ucSendByteInfo, null, PacketFlowControl.CommInfoManualToken, false);

                    await WaitTaskJoin(waitCommandParam, FlowCommandControl, PacketFlowControl.CommInfoManualToken, false);

                    if (QueryResult.bQueryResult)
                        bResult = true;
                    else
                        bResult = false;
                }
            }

            if (bResult)
            {
                if (await ComClientTryConnet(SubscribeConnectInfo.nChangeCommandPort, SubscribeConnectInfo.nChangeStreamPort) == false)
                {
                    AdaptorAbort();

                    bResult = false;
                }
            }

            return bResult;
        }
        
        [ComVisible(true)]
        public bool ComClientTryDisconnect()
        {
            bool bResult = true;

            try
            { 
                ClearCommonVar();

                ClearCommandWatchTask();
                ClearStreamWatchTask();

                ClearCommandClientInstance();
                ClearStreamClientInstance();

                this.ClientCommandErrorEvent(null, null);
                this.ClientStreamErrorEvent(null, null);
            }
            catch (Exception ex)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                   @"Client Disconnect Attempt Error. [SystemX.Net.XAdaptor.PC - IComXPCAdaptor : XPCAdaptor.ComClientTryDisconnect]\r\n" +
                   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return bResult;
        }

        [ComVisible(true)]
        public bool ComCheckConnectState()
        {
            bool bStatus = false;

            try
            {
                thisConnInfo.OnCommandTime();

                try
                {
                    PING_PACKET MakePingPacket = new PING_PACKET();
                    int iSendSize = Marshal.SizeOf(MakePingPacket);
                    byte[] ucSendArray = new byte[iSendSize];
                    MakePingPacket = (PING_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, MakePingPacket.GetType());

                    MakePingPacket.objCheckMsg[0].Data = "Who?";

                    byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.CONNECT_STATE), MakePingPacket);

                    byte ucGetLabel = FlowCommandControl.InsertSendQueue(DateTime.Now, ucSendByteInfo, null, true);

                    if (ComWaitResult(ucGetLabel) == null)
                    {
                        FlowCommandControl.STM.ClearLabel(ucGetLabel);
                    }
                    else
                        bStatus = true;
                }
                catch (Exception ex)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                       @"Command Socket ping check error. [SystemX.Net.XAdaptor.PC - IComXPCAdaptor : XPCAdaptor.ComCheckConnectState]\r\n" +
                       ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }
                finally { }
            }
            finally
            {
                ;
            }

            return bStatus;
        }

        [ComVisible(true)]
        public bool ComCheckConnectStreamState()
        {
            try
            {
                thisConnInfo.OnStreamTime();

                try
                {
                    PING_PACKET MakePingPacket = new PING_PACKET();
                    int iSendSize = Marshal.SizeOf(MakePingPacket);
                    byte[] ucSendArray = new byte[iSendSize];
                    MakePingPacket = (PING_PACKET)SystemXNetSerialization.RawDeSerialize(ucSendArray, MakePingPacket.GetType());

                    MakePingPacket.objCheckMsg[0].Data = "Who?";

                    byte[] ucSendByteInfo = XCommons.SpecialObjectToByteStream(new BASE_PROTOCOL(BASE_PROTOCOL.PROTOCOL_CODE.CONNECT_STATE), MakePingPacket);

                    FlowStreamControl.InsertSendQueue(DateTime.Now, ucSendByteInfo, null);
                }
                catch (Exception ex)
                {
                    MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                       @"Stream Socket ping check error. [SystemX.Net.XAdaptor.PC - IComXPCAdaptor: XPCAdaptor.ComCheckConnectStreamState]\r\n" +
                       ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
                }
                finally { }
            }
            finally
            {
                ;
            }

            return true;
        }

        [ComVisible(true)]
        public string ComSetConfigureFile(string strFilePos)
        {
            if (File.Exists(strFilePos))
            {
                strSetAdaptorConfigFilePos = strFilePos;

                if (CheckConfigFileBuildEndPoint())
                {          
                    return strFilePos;
                }
                else
                    return "";
            }
            else
                return "";
        }
    }
}
