using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using iMESCIO.CDO.Tables;
using iMESCIO.SCI.DPM.Request;
using iMESCIO.SCI.DPM.Response;
using iMESCIO.SCI.ERP.Request;
using iMESCIO.SCI.ERP.Response;
using iMESCIO.SCI.SMES.Request;
using iMESCIO.SCI.SMES.Response;
using iMESCore.Base.ProjectBase.Base;
using iMESCore.Settings;
using MESDAO.Tables;
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
using static iMESCore.DataBase.iMESSql;
using static iMESCore.Base.iMESComSubroutine;

namespace AutoRunLib_C
{

    public class EAIMessageSynchronizer
    {

        public enum WorkCode
        {
            ContinueRun = 0, // 繼續執行作業
            StopSame = 1,    // 停止相同的作業
            StopAll = 2     // 停止所有作業
        }

        private string strDataBaseType;                 // DataBase Type:oracle, mysql, access
        private string strConnectionString;             // Connection string
        private string strReportDataBaseType;
        private string strReportConnectionString;       // Report DB Connection string
        private string strERPconnectionString;
        private string strERPDataBaseType;
        private string strERPReportConnectionString;
        private string InXML, OutXML;
        private string RequestKey = "";
        private AppSettings objSetting = new AppSettings();
        private string strLanguageMode = "zh-cht";
        private string strResourceDir = "Resources";

        // //Initial Object--------------------------------------------------------------------------------------------------------------------------------
        public EAIMessageSynchronizer()
        {
            // //Get database type
            strDataBaseType = objSetting.GetDataBaseType();
            // //Get connection string
            strConnectionString = objSetting.GetConnectionString(strDataBaseType);
            // //Get Message Queue Type
            // strMQType = objSetting.GetMQType()

            strReportDataBaseType = objSetting.GetReportDataBaseType();
            // //Get connection string    
            strReportConnectionString = objSetting.GetReportConnectionString(strReportDataBaseType);

            // ERP
            // //Get ERP database type
            strERPDataBaseType = objSetting.GetDataBaseType_ERP();
            // //Get ERP connection string
            strERPconnectionString = objSetting.GetConnectionString_ERP(strERPDataBaseType);

            try
            {
                strResourceDir = objSetting["ResourceDir"].ToString();
            }
            catch (Exception)
            { }
            try
            {
                strLanguageMode = objSetting["LanguageMode"].ToString();
            }
            catch (Exception)
            {
            }

            // 'T100 整合項目增加,  取得 Web.Config 設定項目, 2015/12/15 Add.

            // Try
            // '從Web.config取出目前的DatabaseType
            // strERPCreator = System.Configuration.ConfigurationSettings.AppSettings.Get("defCreator")
            // '2016-03-09, Joe, 取出預設ERP單位屬性編號
            // strERPUnitNo = System.Configuration.ConfigurationSettings.AppSettings.Get("defERPUnitNoProperty")
            // '2016-03-02, Joe, 取出預設語系並轉換成ERP對應語系，後續T100多語系資料需用到
            // strDefLanguage = System.Configuration.ConfigurationSettings.AppSettings.Get("LanguageMode")
            // Select Case strDefLanguage.ToUpper
            // Case "ZH-CHS"
            // strLanguage_T100 = "zh_CN"
            // Case "EN"
            // strLanguage_T100 = "en_US"
            // Case Else
            // strLanguage_T100 = "zh_TW"
            // End Select
            // Catch ex As Exception
            // '發生錯誤時丟回本身的Function Name及系統錯誤訊息
            // End Try


        }


        // //Property--------------------------------------------------------------------------------------------------------------------------------
        public string ConnectionString
        {
            get
            {
                return strConnectionString;
            }
        }

        public string DataBaseType
        {
            get
            {
                return strDataBaseType;
            }
        }

        public void StartSyncing(Collection colParameters = null)
        {
            var StopRunList = new List<string>();
            var objERPSetting = new List<CDO_TBLSYSERPSETTING>();
            var objQueue = new List<CDO_TBLSYSSENDTOEAIQUEUE>();
            string Parameter01, Parameter02;
            WorkCode ReturnWorkCode;
            bool bSendMail = false;

            do
            {
                try
                {

                    // Parameter01為參數一
                    // 作為Mail通知群組(GroupNo)，放在最前面防止連線失敗無法寄送通知。
                    if (!(colParameters["Parameter01"] == null) & !string.IsNullOrEmpty(Strings.Trim(Conversions.ToString(colParameters["Parameter01"]))))
                    {
                        Parameter01 = colParameters["Parameter01"].ToString().Trim();
                    }
                    else
                    {
                        throw new Exception(TranslateMsg("Mail GroupNo (Parameter 01) [%NOT SET%]!", strLanguageMode, strResourceDir));
                    }

                    // Parameter02為參數二
                    // 重新拋轉上限(數值)
                    if (!(colParameters["Parameter02"] == null) & !string.IsNullOrEmpty(Strings.Trim(Conversions.ToString(colParameters["Parameter02"]))))
                    {
                        if (Information.IsNumeric(colParameters["Parameter02"]) == false)
                        {
                            throw new Exception("(Parameter 02) [%is not%] [%Numeric%]!");
                        }
                        Parameter02 = colParameters["Parameter02"].ToString().Trim();
                    }
                    else
                    {
                        throw new Exception(TranslateMsg("Limit Qty (Parameter 02) [%NOT SET%]!", strLanguageMode, strResourceDir));
                    }

                    // 取得ERP整合設定資訊
                    objERPSetting = GetERPSetting();

                    // 取得要拋送給ERP的資訊
                    objQueue = GetSendQueue();
                    if (objQueue == null)
                        break;

                    string StopData;
                    var SendERPSetting = new CDO_TBLSYSERPSETTING();
                    bool exitTry1 = false;
                    foreach (CDO_TBLSYSSENDTOEAIQUEUE objQ in objQueue)
                    {
                        InXML = "";
                        RequestKey = "";

                        // 找出目前要拋送的目的服務是否有在StopRunList中，如存在則不允許執行
                        StopData = StopRunList.Where(x => (x ?? "") == (objQ.SENDTO ?? "")).FirstOrDefault();
                        if (string.IsNullOrEmpty(StopData))
                        {
                            // 取出要拋送的目的服務的ERP整合設定資訊
                            SendERPSetting = objERPSetting.Where(x => (x.ERP_NAME ?? "") == (objQ.SENDTO ?? "")).FirstOrDefault();
                            if (SendERPSetting == null)
                            {
                                // Throw New Exception("[%ERP_Name%]：" & objQ.SENDTO & "[%IS NOT FOUND%]!")
                                // Exit Try
                                continue;
                            }
                            // 組Req uest XML
                            InXML = CombineRequestXML(SendERPSetting, objQ);
                            // 將資訊拋給ERP
                            using (var ws = new wsERP_EAI.IntegrationEntry())
                            {
                                ws.Url = SendERPSetting.ERP_WSURL;
                                OutXML = ws.invokeSrv(InXML);
                            }
                            // 處理執行結果
                            ReturnWorkCode = HandleSendResult(OutXML, objQ, SendERPSetting, Parameter01, Parameter02);
                            // 依回傳的結果判定是否繼續執行
                            bool exitTry = false;
                            switch (ReturnWorkCode)
                            {
                                case WorkCode.ContinueRun:
                                    {
                                        // 繼續執行
                                        continue;
                                    }
                                case WorkCode.StopSame:
                                    {
                                        // 將此次失敗的ERP名稱加到StopRunList
                                        StopRunList.Add(objQ.SENDTO);
                                        // 繼續執行
                                        continue;
                                    }
                                case WorkCode.StopAll:
                                    {
                                        // 全部停止執行
                                        exitTry1 = exitTry = true;
                                        break;
                                    }
                            }

                            if (exitTry)
                            {
                                break;
                            }
                        }
                    }

                    if (exitTry1)
                    {
                        break;
                    }
                }

                catch (Exception ex)
                {
                    throw;
                }
            }
            while (false);


        }


        /// <summary>
        /// 取得ERP整合的設定資料
        /// </summary>
        /// <returns>List(Of CDO_TBLSYSERPSETTING)</returns>
        private List<CDO_TBLSYSERPSETTING> GetERPSetting()
        {

            var DAO = new DAO_TBLSYSERPSETTING();
            var Data = new List<CDO_TBLSYSERPSETTING>();

            try
            {
                // 取出ERP整合資訊
                Data = (List<CDO_TBLSYSERPSETTING>)DAO.Query(null, new QueryRelatedInfo() { ReturnType = ReturnMode.List });
            }

            catch (Exception ex)
            {
                throw;
            }

            return Data;

        }


        /// <summary>
        /// 取得Queue資料
        /// </summary>
        /// <returns>List(Of CDO_TBLSYSSENDTOEAIQUEUE)</returns>
        private List<CDO_TBLSYSSENDTOEAIQUEUE> GetSendQueue()
        {

            var DAO = new DAO_TBLSYSSENDTOEAIQUEUE();
            var Data = new List<CDO_TBLSYSSENDTOEAIQUEUE>();

            try
            {

                // 取出待拋轉資訊
                Data = (List<CDO_TBLSYSSENDTOEAIQUEUE>)DAO.Query(null, new QueryRelatedInfo() { ReturnType = ReturnMode.List });
            }

            catch (Exception ex)
            {
                throw;
            }

            return Data;

        }

        /// <summary>
        /// 組出RequestXML
        /// </summary>
        /// <returns></returns>
        private string CombineRequestXML(CDO_TBLSYSERPSETTING pERPSetting, CDO_TBLSYSSENDTOEAIQUEUE pSendContent)
        {
            string CombineRequestXMLRet = default(string);

            DataRow[] drERPSetting;
            string strFilter = "";

            try
            {
                // pSendContent.enterprise_no = drERPSetting(0)("ERP_ENTID").ToString
                // pSendContent.site_no = drERPSetting(0)("ERP_ORG").ToString

                // 轉XML
                string RequestHead = "<host prod=\"" + pERPSetting.MESPRODUCTNAME + "\" ver=\"" + pERPSetting.MESPRODUCTVER + "\" ip=\"" + pERPSetting.MESIP + "\" id=\"" + pERPSetting.MESID + "\" acct=\"" + pERPSetting.ERP_USER + "\" lang=\"" + pERPSetting.ERP_LANG + "\" timestamp=\"" + Strings.Format(DateTime.Now, "yyyyMMddHHmmssfff") + "\"/>";
                RequestHead += "<service prod=\"" + pERPSetting.CALLEDPRODUCTNAME + "\" name=\"" + pSendContent.SERVICENAME + "\" ip=\"" + pERPSetting.CALLEDIP + "\" id=\"" + pERPSetting.CALLEDID + "\"/>";
                string RequestDataKey = "<datakey><key name=\"EntId\">" + pERPSetting.ERP_ENTID + "</key><key name=\"CompanyId\">" + pERPSetting.ERP_ORG + "</key></datakey>";
                string RequestXML_Body = pSendContent.PAYLOAD;
                RequestKey = modAutoRunLibrary.GetRequestKey(RequestHead);
                string RequestHeader = "<request key=\"" + RequestKey + "\" type=\"sync\">" + RequestHead + RequestDataKey + "<payload>" + RequestXML_Body + "</payload></request>";
                // CDO to XML
                CombineRequestXMLRet = RequestHeader;
            }

            catch (Exception ex)
            {
                throw;
            }

            return CombineRequestXMLRet;

        }

        /// <summary>
        /// 同步結果處理
        /// </summary>
        /// <returns></returns>
        private WorkCode HandleSendResult(string pEAIResult, CDO_TBLSYSSENDTOEAIQUEUE pSendSrc, CDO_TBLSYSERPSETTING pEAISetting, string pJobParam01, string pJobParam02)
        {
            WorkCode HandleSendResultRet = default(WorkCode);

            //IDbConnection cnnTemp = null;
            //IDbCommand cmmTemp;
            string strSQL;
            //System.Data.OleDbDataAdapter daTemp;
            var dsTemp = new DataSet();
            var objReturn = default(WorkCode);
            var objEAIResult = default(object);
            bool ProcessResult = false;
            string ProcessMessage = "";

            try
            {
                // 物件初始化
                switch (pSendSrc.SERVICENAME ?? "")
                {
                    case "issue.wo.item.process":    // MES發料
                        {
                            objEAIResult = new SCI_Response_issue_wo_item_process();
                            break;
                        }
                    case "stockin.data.create":  // 完工入庫
                        {
                            objEAIResult = new SCI_Response_stockin_data_create();
                            break;
                        }
                    case "workorder.create": // DPM 拋報工單
                        {
                            objEAIResult = new SCI_Response_workorder_create();
                            break;
                        }
                }
                // 將中台回的結果轉成物件
                try
                {
                    (objEAIResult as SCI_Response_workorder_create).ParseXmlToObject(pEAIResult);
                    if (Conversions.ToBoolean(Operators.ConditionalCompareObjectEqual((objEAIResult as SCI_Response_workorder_create).code, "0", false)))
                    {
                        ProcessResult = true;
                    }
                    else
                    {
                        ProcessMessage = Conversions.ToString((objEAIResult as SCI_Response_workorder_create).description);
                    }
                }
                catch (Exception ex)
                {
                    ProcessMessage = OutXML;
                }
                // 紀錄TransactionLog
                string argstrException = null;
                modAutoRunLibrary.addTransactionLog(InXML, OutXML, DateTime.Now.ToString("yyyyMMddHHmmssss"), "MES", "StartSyncing", Environment.MachineName, "AutoRun", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), Conversions.ToString(Interaction.IIf(ProcessResult == Conversions.ToBoolean("0"), "success", "fail")), ProcessMessage, pSendSrc.SERVICENAME, strException: argstrException);
                // 判斷中台回的結果
                if (ProcessResult)
                {
                    // 成功
                    HandleSendResultRet = WorkCode.ContinueRun;
                    // 處理執行成功資訊及歷程
                    HandleSendSuccess(pEAIResult, pSendSrc);
                }
                else
                {
                    // 失敗
                    // 處理執行失敗資訊及歷程
                    HandleSendFail(pEAIResult, ProcessMessage, pSendSrc, pJobParam02);
                    // 寄送Mail
                    string argFileName = "N/A";
                    string argEmailSubject = "AutuRunJob : StartSyncing Fail![" + pSendSrc.SERVICENAME + "]";
                    string argEmailBody = TranslateMsg("[%SENDID%]：" + pSendSrc.SENDID + " [%EXECUTE%] [%ISSUEMOMATERIAL%] [%FAIL%]! [%ERRORMESSAGE%]：", strLanguageMode, strResourceDir) + ProcessMessage;
                    modAutoRunLibrary.SendMultiEmail(ref argFileName, ref argEmailSubject, argEmailBody, pJobParam01);
                }
            }

            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                //CloseConnection(cnnTemp);
            }

            return objReturn;

        }

        /// <summary>
        /// 同步結果處理-成功
        /// </summary>
        /// <returns></returns>
        private void HandleSendSuccess(string pEAIResult, CDO_TBLSYSSENDTOEAIQUEUE pSendSrc)
        {

            string strSQL;
            var objQueueLog = new CDO_TBLSYSSENDTOEAIQUEUE_LOG();
            var objEAIResult = new object();
            var DAO = new DAO_TBLSYSSENDTOEAIQUEUE();
            var DAO_Log = new DAO_TBLSYSSENDTOEAIQUEUE_LOG();

            var cdoERPDocLog = new CDO_TBLSYSERPDOCUMENTLOG();
            var daoERPDocLog = new DAO_TBLSYSERPDOCUMENTLOG();

            try
            {
                // 執行成功後呼叫各服務各自處理邏輯
                switch (pSendSrc.SERVICENAME ?? "")
                {
                    case "issue.wo.item.process":    // MES發料
                        {
                            objEAIResult = new SCI_Response_issue_wo_item_process();
                            // 將中台回的結果轉成物件
                            try
                            {
                                (objEAIResult as SCI_Response_issue_wo_item_process).ParseXmlToObject(pEAIResult);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("[%XML FORMAT ERROR%]");
                            }

                            // 解析Request XML
                            var cdoInXML = new SCI_Request_issue_wo_item_process();
                            cdoInXML.ParseXmlToObject(InXML);

                            object argdaoTransaction = DAO;
                            AddERPDocumentLog(8, Conversions.ToString((objEAIResult as SCI_Response_issue_wo_item_process).return_no), cdoInXML.doc_no, pSendSrc, ref argdaoTransaction);
                            DAO = (DAO_TBLSYSSENDTOEAIQUEUE)argdaoTransaction;
                            break;
                        }
                    case "stockin.data.create":  // 完工入庫
                        {
                            objEAIResult = new SCI_Response_stockin_data_create();
                            // 將中台回的結果轉成物件
                            try
                            {
                                (objEAIResult as SCI_Response_stockin_data_create).ParseXmlToObject(pEAIResult);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("[%XML FORMAT ERROR%]");
                            }

                            // 解析Request XML
                            var cdoInXML = new SCI_Request_stockin_data_create();
                            cdoInXML.ParseXmlToObject(InXML);

                            object argdaoTransaction1 = DAO;
                            AddERPDocumentLog(4, Conversions.ToString((objEAIResult as SCI_Response_stockin_data_create).stock_in_no), cdoInXML.source_no, pSendSrc, ref argdaoTransaction1);
                            DAO = (DAO_TBLSYSSENDTOEAIQUEUE)argdaoTransaction1;
                            break;
                        }

                    case "workorder.create":  // DPM報工單
                        {
                            objEAIResult = new SCI_Response_workorder_create();
                            // 將中台回的結果轉成物件
                            try
                            {
                                (objEAIResult as SCI_Response_workorder_create).ParseXmlToObject(pEAIResult);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("[%XML FORMAT ERROR%]");
                            }

                            // 解析Request XML
                            var cdoInXML = new SCI_Request_workorder_create();
                            cdoInXML.ParseXmlToObject(InXML);
                            break;
                        }
                }

                // 將Queue資訊搬至Log
                objQueueLog.SENDID = pSendSrc.SENDID;
                objQueueLog.SENDTO = pSendSrc.SENDTO;
                objQueueLog.SERVICENAME = pSendSrc.SERVICENAME;
                objQueueLog.SERVICEVERSION = pSendSrc.SERVICEVERSION;
                objQueueLog.SENDCONTENT = pSendSrc.PAYLOAD;
                objQueueLog.SENDCOUNT = pSendSrc.SENDCOUNT;
                objQueueLog.RETURNINFO = Conversions.ToString((objEAIResult as SCI_Response_workorder_create).description);
                objQueueLog.RUNRESULT = "success";
                objQueueLog.CREATOR = pSendSrc.CREATOR;
                objQueueLog.CREATEDATE = pSendSrc.CREATEDATE;
                // 2017-07-17, Joe, 將ERP入庫單號寫入Queue中，還原時才能與MES發料資訊做對應一起還原
                objQueueLog.RELATIONERPNO = pSendSrc.RELATIONERPNO;
                objQueueLog.LOTSERIAL = pSendSrc.LOTSERIAL;
                DAO_Log.Add(objQueueLog, DAO);

                // 刪除已拋轉成功的Queue
                DAO.Delete(pSendSrc, DAO);
            }

            catch (Exception ex)
            {
                throw;
            }
            finally
            {
            }

        }

        /// <summary>
        /// 同步結果處理-失敗
        /// </summary>
        /// <returns></returns>
        private void HandleSendFail(string pEAIResult, string pEAIMessage, CDO_TBLSYSSENDTOEAIQUEUE pSendSrc, string pJobParam02)
        {

            string strSQL;
            var objQueueLog = new CDO_TBLSYSSENDTOEAIQUEUE_LOG();
            var DAO = new DAO_TBLSYSSENDTOEAIQUEUE();
            var DAO_Log = new DAO_TBLSYSSENDTOEAIQUEUE_LOG();

            try
            {
                // 錯誤次數加1
                pSendSrc.SENDCOUNT = pSendSrc.SENDCOUNT + 1;
                pSendSrc.EXCEPTION = pEAIResult;

                // 將此筆Queue回寫DB
                DAO.Update(pSendSrc, DAO);

                // 發送Mail

                // 判斷目前執行的同步次數是否已達到最大限制次數
                if (string.IsNullOrEmpty(pJobParam02) == false && Convert.ToInt32(pJobParam02) != -1 && pSendSrc.SENDCOUNT > Convert.ToInt32(pJobParam02))
                {

                    // 將Queue資訊搬至Log
                    objQueueLog.SENDID = pSendSrc.SENDID;
                    objQueueLog.SENDTO = pSendSrc.SENDTO;
                    objQueueLog.SERVICENAME = pSendSrc.SERVICENAME;
                    objQueueLog.SERVICEVERSION = pSendSrc.SERVICEVERSION;
                    objQueueLog.SENDCONTENT = pSendSrc.PAYLOAD;
                    objQueueLog.SENDCOUNT = pSendSrc.SENDCOUNT;
                    objQueueLog.RETURNINFO = pEAIMessage;
                    objQueueLog.RUNRESULT = "fail";
                    objQueueLog.EXCEPTION = pSendSrc.EXCEPTION;
                    objQueueLog.CREATOR = pSendSrc.CREATOR;
                    objQueueLog.CREATEDATE = pSendSrc.CREATEDATE;
                    // 2017-07-17, Joe, 將ERP入庫單號寫入Queue中，還原時才能與MES發料資訊做對應一起還原
                    objQueueLog.RELATIONERPNO = pSendSrc.RELATIONERPNO;
                    DAO_Log.Add(objQueueLog, DAO);

                    // 刪除已拋轉成功的Queue
                    DAO.Delete(pSendSrc, DAO);

                }
            }

            catch (Exception ex)
            {
                throw;
            }
            finally
            {
            }

        }

        private object AddERPDocumentLog(int pDocType, string ERPNo, string MESNo, CDO_TBLSYSSENDTOEAIQUEUE pSendSrc, ref object daoTransaction)
        {

            var cdoERPDocLog = new CDO_TBLSYSERPDOCUMENTLOG();
            var daoERPDocLog = new DAO_TBLSYSERPDOCUMENTLOG();

            try
            {
                // 將資訊寫入ERP Document Log
                cdoERPDocLog.TRANSID = RequestKey;
                cdoERPDocLog.DOCUMENTTYPE = pDocType;   // 單據類別 1:工單發料，2:工單退料，3:報工單，4:完工入庫，5:不良品入庫單，6:外包出貨單，7:外包回貨單，8：MES發料
                cdoERPDocLog.MESNO = MESNo;
                cdoERPDocLog.ERPNO = ERPNo;
                cdoERPDocLog.CREATEDATE = pSendSrc.CREATEDATE;
                // 2017-07-17, Joe, 將ERP入庫單號寫入Queue中，還原時才能與MES發料資訊做對應一起還原
                cdoERPDocLog.RELATIONERPNO = pSendSrc.RELATIONERPNO;
                cdoERPDocLog.SENDID = pSendSrc.SENDID;
                daoERPDocLog.Add(cdoERPDocLog, (iMESDBBase)daoTransaction);
            }

            catch (Exception ex)
            {
                throw;
            }

            return default(Object);
        }

    }
}