//#define LOG_TRACE   //@@ 2017.11.01;로그 확인시 사용;girak.kim
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;

using Newtonsoft.Json;

using Cosmos.BaseFrame;
using Cosmos.UserFrame;
using Cosmos.ServiceProvider;
using Cosmos.Common;

/*-----------------------------------------------------------------------------------------------*/
// 설      명 : SC / HQ IRT Request (SC / 본부 IRT 요청)
// 작  성  자 : 
// 변경  이력 : 
/*-----------------------------------------------------------------------------------------------*/
namespace Cosmos.BackgroundDown
{
    public class NetworkJSON
    {
        private SManager sManager = new SManager();                                 // 이 객체를 통해 업무 Service 호출
        private StateServer StateObject = (StateServer)StateServer.GetInstance();   // StateObject : StateServer Object (객체)
        private PosStatus m_cPosStatus;                                             // 기본정보 참조
        private DeviceStatus m_cDevStatus;                                          // 장비정보 참조 

        /// <summary>
        /// Sending Socket (전송 소켓)
        /// </summary>
        private static TcpSocket m_IrtSocket = null;

        /// <summary>
        /// IP
        /// </summary>
        private string m_ServerIp = "";

        /// <summary>
        /// Port
        /// </summary>
        private int m_ServerPort = 0;

        /// <summary>
        /// Recv Timeout
        /// </summary>
        private int m_ServerTimeout = 5000;


        /// ---------------------------------------------------------------------------------------------
        /// <summary>
        /// Constructor (생성자)
        /// </summary>
        /// ---------------------------------------------------------------------------------------------
        public NetworkJSON()
        {
            m_cPosStatus = (PosStatus)StateObject.POS;                              // POS 기본정보
            m_cDevStatus = (DeviceStatus)StateObject.DEVICE;                        // POS 장치정보
        }

        /// <summary>
        /// Get network online status with Ping check. (Ping체크로 network Online상태를 취득한다,)
        /// </summary>
        /// <param name="pHostAddress">Ip address</param>
        /// <returns>True : online  false : Offline</returns>
        private int CheckNetworkOnline(string pHostAddress)
        {
            //Ping Check (Ping 체크)
            Ping pingSender = new Ping();
            PingOptions optins = new PingOptions();
            optins.DontFragment = true;
            string data = "aaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            int timeout = 120;
            PingReply reply = pingSender.Send(pHostAddress, timeout, buffer, optins);

            if (reply.Status == IPStatus.Success)
                return UserCom.OK;
            else
                return UserCom.NG;
        }
/*
        #region 암호화 편집
        /// <summary>
        /// 암호화 위해 전문 편집
        /// </summary>
        /// <param name="plainData">평문</param>
        /// <returns>암호문, 에러시 평문 리턴</returns>
        private byte[] EncryptData(byte[] plainData)
        {
            int nNowPos = 0;

            //통신헤더전문편집
            string[] aCommHead = new string[Column.COMM_HEADER.LEN.Length];
            ItemColumn.ParseMessage(Column.COMM_HEADER.LEN, Column.COMM_HEADER.TYPE, plainData, ref nNowPos, ref aCommHead);

            string sPosNo = aCommHead[Column.COMM_HEADER.SEQ.PosNo].ToString();
            //string sRegNo = aCommHead[Column.COMM_HEADER.SEQ.RegNo].ToString();
            string sRegNo = "";
            string sMsgLen = aCommHead[Column.COMM_HEADER.SEQ.MsgLen].ToString();
            string sEncType = aCommHead[Column.COMM_HEADER.SEQ.EncType].ToString();
            byte[] byteEncryptData = null;
            byte[] editedAllData = null;

            if (sEncType == "0") // "0" 평문
            {
                //Tran헤더 포함 전문 데이터
                byte[] tranBytes = new byte[plainData.Length - nNowPos];

                Array.Copy(plainData, nNowPos, tranBytes, 0, plainData.Length - nNowPos);

                //암호화
                byteEncryptData = AES.DynamicKeyEncrypt(sPosNo, sRegNo, tranBytes);

                int iMsgLen = nNowPos + byteEncryptData.Length;

                aCommHead[Column.COMM_HEADER.SEQ.MsgLen] = iMsgLen.ToString();  //공통헤더와 암호문 더해진 길이
                aCommHead[Column.COMM_HEADER.SEQ.EncType] = "1";                //0:평문 1:암호화

                string sChangedCommHeader = ItemColumn.MakeMessage(aCommHead, Column.COMM_HEADER.LEN, Column.COMM_HEADER.TYPE);
                byte[] byteCommHeader = Encoding.Default.GetBytes(sChangedCommHeader);

                editedAllData = new byte[iMsgLen];
                Array.Copy(byteCommHeader, editedAllData, byteCommHeader.Length);
                Array.Copy(byteEncryptData, 0, editedAllData, byteCommHeader.Length, byteEncryptData.Length);

                return editedAllData;
            }
            else // "1" 암호문
            {
                return plainData;
            }

        }

        #endregion

        #region 복호화 편집
        /// <summary>
        /// 복호화 위해 전문 편집
        /// </summary>
        /// <param name="EncryptData"></param>
        /// <returns></returns>
        private byte[] DecryptData(byte[] EncryptData)
        {
            int nNowPos = 0;

            //통신헤더전문편집
            string[] aCommHead = new string[Column.COMM_HEADER.LEN.Length];
            ItemColumn.ParseMessage(Column.COMM_HEADER.LEN, Column.COMM_HEADER.TYPE, EncryptData, ref nNowPos, ref aCommHead);

            string sPosNo = aCommHead[Column.COMM_HEADER.SEQ.PosNo].ToString();
            //string sRegNo = aCommHead[Column.COMM_HEADER.SEQ.RegNo].ToString();
            string sRegNo = "";
            string sMsgLen = aCommHead[Column.COMM_HEADER.SEQ.MsgLen].ToString();
            string sEncType = aCommHead[Column.COMM_HEADER.SEQ.EncType].ToString();
            byte[] bytePlainData = null;
            byte[] editedAllData = null;

            if (sEncType == "1")    //복호화
            {
                //Tran헤더 포함 전문 데이터
                byte[] tranBytes = new byte[EncryptData.Length - nNowPos];

                Array.Copy(EncryptData, nNowPos, tranBytes, 0, tranBytes.Length);

                //복호화
                bytePlainData = AES.DynamicKeyDecrypt(sPosNo, sRegNo, tranBytes);

                int iMsgLen = nNowPos + bytePlainData.Length;

                aCommHead[Column.COMM_HEADER.SEQ.MsgLen] = iMsgLen.ToString();  //공통헤더와 암호문 더해진 길이
                aCommHead[Column.COMM_HEADER.SEQ.EncType] = "0";                //0:평문 1:암호화

                string sChangedCommHeader = ItemColumn.MakeMessage(aCommHead, Column.COMM_HEADER.LEN, Column.COMM_HEADER.TYPE);

                byte[] byteCommHeader = Encoding.Default.GetBytes(sChangedCommHeader);
                editedAllData = new byte[byteCommHeader.Length + bytePlainData.Length];

                Array.Copy(byteCommHeader, editedAllData, byteCommHeader.Length);
                Array.Copy(bytePlainData, 0, editedAllData, byteCommHeader.Length, bytePlainData.Length);

                return editedAllData;

            }
            else
            {
                return EncryptData;
            }

        }

        #endregion
*/
        /// <summary>
        /// POS 마스터 요청 시 사용하는 Connect 함수
        /// </summary>
        /// <returns></returns>
        private int Connect(int iKeepTime = 5000)
        {
            int iReturn = BaseCom.NG;
            try
            {
                m_IrtSocket = new TcpSocket(m_ServerIp, m_ServerPort, m_ServerTimeout);

                // Delay time to close connection is 5 sec.
                iReturn = m_IrtSocket.Connect(iKeepTime);
            }
            catch (Exception e)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    "NetworkJSON.Connect()", e.ToString());
            }

            return iReturn;
        }

        private void Close()
        {
            m_IrtSocket.Close();
        }



        /// <summary>
        /// IRT전문의 Send/Receive
        /// </summary>
        /// <param name="pSendData"></param>
        /// <param name="pRecvData"></param>
        /// <returns></returns>
        private int SendReceiveData(byte[] pSendData, ref byte[] pRecvData)
        {
            int nRecvLen = 0;
            int nStat = BaseCom.NG;
            byte[] rRecvData = null;

            try
            {
                m_IrtSocket = new TcpSocket(m_ServerIp, m_ServerPort, m_ServerTimeout);

                // Data Send & Receive
                nRecvLen = m_IrtSocket.SendReceiveData(pSendData, ref rRecvData, m_ServerTimeout);

                if (nRecvLen > 0)
                {
                    pRecvData = rRecvData;
                    nStat = BaseCom.OK;
                }
                else
                {
                    pRecvData = null;
                }
                m_IrtSocket.Close();
            }
            catch (Exception e)
            {
                if (m_IrtSocket != null) m_IrtSocket.Close();
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    "NetworkJSON.SendReceiveData()", "NetworkIrt Error : ThreadNetworkIrt Exception !!! " + e.ToString());
            }
            finally
            {
            }
            System.Threading.Thread.Sleep(100);
            return nStat;
        }

        /// <summary>
        /// IRT전문의 Send/Receive
        /// </summary>
        /// <param name="pSendData"></param>
        /// <param name="pRecvData"></param>
        /// <returns></returns>
        private int SendReceiveData(string pSendData, ref string pRecvData, bool bIsDmbIf = false)
        {
            int nRecvLen = 0;
            int nStat = BaseCom.NG;
            string rRecvData = "";

            try
            {
                m_IrtSocket = new TcpSocket(m_ServerIp, m_ServerPort, m_ServerTimeout);

                // Data Send & Receive
                //System.Diagnostics.Debug.Print("요청:" + pSendData);
                nRecvLen = m_IrtSocket.SendReceiveData(pSendData, ref rRecvData, m_ServerTimeout, bIsDmbIf);
                //System.Diagnostics.Debug.Print("응답:" + rRecvData);

                if (nRecvLen > 0)
                {
                    pRecvData = rRecvData;
                    nStat = BaseCom.OK;
                }
                else
                {
                    pRecvData = "";
                    nStat = nRecvLen;
                }
                m_IrtSocket.Close();
            }
            catch (Exception e)
            {
                if (m_IrtSocket != null) m_IrtSocket.Close();
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    "NetworkJSON.SendReceiveData()", "NetworkIrt Error : ThreadNetworkIrt Exception !!! " + e.ToString());
            }
            finally
            {
            }

            System.Threading.Thread.Sleep(100);
            return nStat;
        }

        private int SendReceiveMstData(string pSendData, ref string pRecvData)
        {
            int nRecvLen = 0;
            int nStat = BaseCom.NG;
            try
            {
                nRecvLen = m_IrtSocket.SendReceiveMstData(pSendData, ref pRecvData);
                if (nRecvLen > 0)
                {
                    nStat = BaseCom.OK;
                }
            }
            catch (Exception e)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                                    e.ToString());
            }

            return nStat;
        }
        
        /// <summary>
        /// IRT Byte로의 Send/Recv
        /// (공통헤더의 전문길이 0으로 세팅해서 송신. 자동 계산)
        /// </summary>
        /// <param name=""></param>
        public int IRTSendReceive(string sIP, int iPort, int iTimeOut, string sCommData, Hashtable htData, ref Hashtable htRecvData)
        {
            int nStat = 9;
            string sReturn = string.Empty;
            string sRecvCommHeader = string.Empty;
            string sRecvData = string.Empty;

            m_ServerIp = sIP;
            m_ServerPort = iPort;
            m_ServerTimeout = iTimeOut;

            string sJsonSendData = "";
            string sJsonReceiveData = "";

            try
            {
                if (m_ServerIp != "" && m_ServerPort != 0)
                {
                    if (htData != null)
                    {
                        sJsonSendData = JsonConvert.SerializeObject(htData);

                        //sJsonSendData 암호화 처리 ...

                        Byte[] sBytTempBuff = Encoding.UTF8.GetBytes(sJsonSendData);
                        string sDataLen = string.Format("{0:000000}", sBytTempBuff.Length);

                        sCommData = sDataLen + sCommData.Substring(TcpSocket.COMM_MSGLEN);

                        UserLog.WriteLogFile(UserCom.LOG_SOCK, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                                            "NetworkJSON.IRTSendReceive()", CmUtil.RPadH("[SEND" + ":" + m_ServerIp + ":" + m_ServerPort, 27) + "] " + sCommData + sJsonSendData);
                    }

                    //Send Receive
                    nStat = SendReceiveData(sCommData + sJsonSendData, ref sJsonReceiveData);

                    if (sJsonReceiveData != null && sJsonReceiveData != "")
                    {
                        sRecvCommHeader = sJsonReceiveData.Substring(0, TcpSocket.COMM_HEAD_LEN);
                        sRecvData = sJsonReceiveData.Substring(TcpSocket.COMM_HEAD_LEN);
                        //sJsonReceiveData 복호화 처리 ...

                        htRecvData = JsonConvert.DeserializeObject<Hashtable>(sRecvData);

                        UserLog.WriteLogFile(UserCom.LOG_SOCK, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                                            "NetworkJSON.IRTSendReceive()", CmUtil.RPadH("[RECV" + ":" + m_ServerIp + ":" + m_ServerPort, 27) + "] " + sRecvCommHeader + sRecvData);
                    }
                }
            }
            catch (Exception e)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    "NetworkJSON.IRTSendReceive()", e.ToString());
            }

            return nStat;
        }
        /// <summary>
        /// 디지털메뉴보드 I/F용 send/receive
        /// </summary>
        /// <param name="sIP"></param>
        /// <param name="iPort"></param>
        /// <param name="iTimeOut"></param>
        /// <param name="sCommData"></param>
        /// <param name="htData"></param>
        /// <param name="sRecvedData"></param>
        /// <returns></returns>
        public int DmbIRTSendReceive(string sIP, int iPort, int iTimeOut, string sCommData, Hashtable htData, ref string sRecvedData)
        {
            int nStat = 9;
            string sReturn = string.Empty;
            string sRecvCommHeader = string.Empty;
            string sRecvData = string.Empty;

            m_ServerIp = sIP;
            m_ServerPort = iPort;
            m_ServerTimeout = iTimeOut;

            string sJsonSendData = "";
            string sJsonReceiveData = "";

            try
            {
                if (m_ServerIp != "" && m_ServerPort != 0)
                {
                    if (htData != null)
                    {
                        sJsonSendData = JsonConvert.SerializeObject(htData);

                        //sJsonSendData 암호화 처리 ...
                        
                        UserLog.WriteLogFile(UserCom.LOG_SOCK, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                                            "NetworkJSON.IRTSendReceive()", CmUtil.RPadH("[SEND" + ":" + m_ServerIp + ":" + m_ServerPort, 27) + "] " + sCommData + sJsonSendData);
                    }

                    byte[] bytes = Encoding.UTF8.GetBytes(sCommData + sJsonSendData);
                    string sUTF8String = Encoding.UTF8.GetString(bytes);
                                        
                    //Send Receive
                    //nStat = SendReceiveData(sCommData + sJsonSendData, ref sJsonReceiveData, true);
                    nStat = SendReceiveData(sUTF8String, ref sJsonReceiveData, true);
                    
                    if (sJsonReceiveData != null && sJsonReceiveData != "")
                    {
                        sRecvCommHeader = sJsonReceiveData.Substring(0, 60);
                        sRecvData = sJsonReceiveData.Substring(60);

                        sRecvedData = sRecvCommHeader;

                        UserLog.WriteLogFile(UserCom.LOG_SOCK, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                                            "NetworkJSON.IRTSendReceive()", CmUtil.RPadH("[RECV" + ":" + m_ServerIp + ":" + m_ServerPort, 27) + "] " + sRecvCommHeader + sRecvData);
                    }
                }
            }
            catch (Exception e)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    "NetworkJSON.IRTSendReceive()", e.ToString());
            }

            return nStat;
        }
        
        /// <summary>
        /// 마스터 요청을 위한 string으로의 send/receive
        /// </summary>
        /// <param name="sIp"></param>
        /// <param name="iPort"></param>
        /// <param name="iTimeOut"></param>
        /// <param name="sCommData"></param>
        /// <param name="htData"></param>
        /// <param name="sbRecvData"></param>
        /// <returns></returns>
        public int MstIRTSendReceive(string sIp, int iPort, int iTimeOut, string sCommData, Hashtable htData, ref StringBuilder sbRecvData)
        {
            int nStat = BaseCom.NG;
            string sRecvCommHeader = string.Empty;
            string sRecvData = string.Empty;

            try
            {
                m_ServerIp = sIp;
                m_ServerPort = iPort;
                m_ServerTimeout = iTimeOut;

                string sJsonSendData = string.Empty;
                string sJsonReceiveData = string.Empty;
                Hashtable htRecvData = null;

                sbRecvData = new StringBuilder();

                nStat = Connect(-1);

                if(nStat == BaseCom.OK)
                {
                    while (true)
                    {
                        sJsonSendData = JsonConvert.SerializeObject(htData);

                        //sJsonSendData 암호화 처리 ...

                        Byte[] sBytTempBuff = Encoding.UTF8.GetBytes(sJsonSendData);
                        string sDataLen = string.Format("{0:000000}", sBytTempBuff.Length);

                        sCommData = sDataLen + sCommData.Substring(TcpSocket.COMM_MSGLEN);

                        // 마스터 송수신 로그 제거(20170520)
                        //UserLog.WriteLogFile(UserCom.LOG_SOCK,
                        //                     UserCom.WARNING_LEVEL,
                        //                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                        //                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                        //                     CmUtil.RPadH("[SEND" + ":" + m_ServerIp + ":" + m_ServerPort, 27) + "] " + sCommData + sJsonSendData);

                        #if(LOG_TRACE)   ////@@ 로그 확인 용
                                                UserLog.WriteLogFile(UserCom.LOG_OP, "Background NetJson SendData : ", System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name + "," + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()", sCommData + sJsonSendData);
                        #endif
                        // 전문 송신
                        nStat = SendReceiveMstData(sCommData + sJsonSendData, ref sJsonReceiveData);
                        
                        #if(LOG_TRACE)   ////@@ 로그 확인 용
                                                UserLog.WriteLogFile(UserCom.LOG_OP, "Background NetJson RecvData : ", System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name + "," + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name + "()", sJsonReceiveData);
                        #endif                    
                        
                        if (nStat == BaseCom.OK)
                        {
                            // 마스터 송수신 로그 제거(20170520)
                            //UserLog.WriteLogFile(UserCom.LOG_SOCK,
                            //                     UserCom.WARNING_LEVEL,
                            //                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                            //                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                            //                     CmUtil.RPadH("[RECV" + ":" + m_ServerIp + ":" + m_ServerPort, 27) + "] " + sJsonReceiveData);

                            if (sJsonReceiveData != null && sJsonReceiveData != string.Empty)
                            {
                                sRecvCommHeader = sJsonReceiveData.Substring(0, TcpSocket.COMM_HEAD_LEN);
                                sRecvData = sJsonReceiveData.Substring(TcpSocket.COMM_HEAD_LEN);

                                //sRecvData 복호화 처리 ...
                                
                                htRecvData = JsonConvert.DeserializeObject<Hashtable>(sRecvData);

                                if (int.Parse(htRecvData[Column.IQ_POSMASTER_RSP.DATA.Count].ToString().Trim()) != 0)
                                {
                                    // StringBuilder에 추가
                                    sbRecvData.Append(htRecvData[Column.IQ_POSMASTER_RSP.DATA.Data].ToString());
                                }
                                else
                                {
                                    break;
                                }
                                // 요청전문의 요청 코드 변경
                                htData[Column.IQ_POSMASTER_REQ.DATA.ProcCd] = "1";
                            }
                        }
                        else
                        {
                            return BaseCom.NG1;
                        }
                    }

                    nStat = BaseCom.OK;
                }
            }
            catch (Exception e)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                    "NetworkJSON.MstIRTSendReceive()", e.ToString());
            }
            finally
            {
                Close();
            }

            return nStat;
        }
    }
}
