/// <summary>
        /// Response物件建立MAC並依據規格書轉換成byte[]
        /// </summary>
        /// <param name="msgUtility">Response Msg Parser</param>
        /// <param name="response">後端給的POCO</param>
        /// <param name="request">Origin Request byte array</param>
        /// <param name="doMAC">是否產生MAC:驗證失敗就使用來源的mac</param>
        /// <returns>response byte array</returns>
        protected virtual byte[] ParseResponse(IMsgUtility msgUtility, POL_Domain response, byte[] request, bool doMAC = true)
        {
            log.Debug(m => m("7.轉換後台Response物件並建立MAC並轉成Response Byte[]"));
            byte[] rspResult = new byte[request.Length];
            Buffer.BlockCopy(request, 0, rspResult, 0, request.Length);//

            // modify request to response
            msgUtility.SetStr("02", rspResult, "Communicate");
            msgUtility.SetStr(response.PCHR_RC, rspResult, "ReturnCode");
            msgUtility.SetStr(response.PCHR_SN, rspResult, "CenterSeqNo");
            msgUtility.SetStr(this.amount, rspResult, "Amount");

            msgUtility.SetStr(this.transDateTime, rspResult, "TransDateTime");
            //是否產生mac
            if (doMAC)
            {
                // fetch sha1 data
                this.SetMAC(msgUtility, rspResult, this.readerId, this.transDateTime);
            }
            else
            {
                //若Mac驗證失敗,則使用來源mac簡易回傳
                msgUtility.SetStr(this.mac, rspResult, "Mac");
            }
            // padding data
            this.SetPadding(msgUtility, rspResult);
            return(rspResult);
        }
        /// <summary>
        /// Request依據規格書截取需要的資料轉成POCO
        /// </summary>
        /// <param name="msgUtility">Request Msg Parser</param>
        /// <param name="msgBytes">Origin Request byte array</param>
        /// <returns>POCO</returns>
        protected virtual POL_Domain ParseRequest(IMsgUtility msgUtility, byte[] msgBytes)
        {
            log.Debug("3.開始轉換購貨取消Request物件");
            POL_Domain oLDomain = new POL_Domain();

            //ComType:0332
            oLDomain.COM_TYPE = msgUtility.GetStr(msgBytes, "ReqType");

            oLDomain.POS_FLG = msgUtility.GetStr(msgBytes, "ReaderType");

            oLDomain.READER_ID = this.readerId;//CheckMacContainer.AOLReqMsgUtility.GetStr(msgBytes, "ReaderId").Substring(0, 16);

            oLDomain.MERC_FLG = msgUtility.GetStr(msgBytes, "MercFlg");

            oLDomain.STORE_NO = msgUtility.GetStr(msgBytes, "StoreNo");

            oLDomain.REG_ID = msgUtility.GetStr(msgBytes, "RegId");

            // modify StoreNo and RegId
            if ("SET".Equals(oLDomain.MERC_FLG))
            {
                oLDomain.STORE_NO = oLDomain.STORE_NO.Substring(2, 6);
                oLDomain.REG_ID   = oLDomain.REG_ID.Substring(1, 2);
            }

            //
            oLDomain.PCHR_AMT = Convert.ToInt32(this.amount);
            //
            oLDomain.ICC_NO = msgUtility.GetStr(msgBytes, "CardNo");

            log.Debug("4.結束轉換購貨取消Request物件");
            return(oLDomain);
        }
        /// <summary>
        /// 處理邏輯
        /// </summary>
        /// <param name="handler"></param>
        public void Handle(ClientRequestHandler handler)
        {
            try
            {
                POL_Domain request     = null;
                bool       doMac       = true;
                POL_Domain response    = null;
                byte[]     responseArr = null;
                log.Debug(m => m("[State_PurchaseReturn] {0} Request(ASCII):{1}", handler.ClientSocket.RemoteEndPoint.ToString(), ClientRequestHandler.asciiOctets2String(handler.Request)));
                //1.驗證Mac
                if (this.CheckMac(CheckMacContainer.PRReqMsgUtility, handler.Request))
                {
                    //2.parse request
                    request = this.ParseRequest(CheckMacContainer.PRReqMsgUtility, handler.Request);
                    //3.send to Back-End request and get response
                    response = this.GetResponse(request);
                    if (response == null || string.IsNullOrEmpty(response.PCHR_RC))
                    {
                        //back-End Error
                        response = new POL_Domain()
                        {
                            PCHR_SN = "99999999",
                            PCHR_RC = "990001"
                        };
                    }
                }
                else
                {
                    //MAC驗證失敗
                    doMac    = false;
                    response = new POL_Domain()
                    {
                        PCHR_SN = "99999999",
                        PCHR_RC = "990001"
                    };
                }

                //4. parse response byte array(create mac)
                responseArr = this.ParseResponse(CheckMacContainer.PRRespMsgUtility, response, handler.Request, doMac);

                log.Info(m => m("Response(length:{0}):{1}", responseArr.Length, BitConverter.ToString(responseArr).Replace("-", "")));
                int sendLength = handler.ClientSocket.Send(responseArr);
                if (sendLength != responseArr.Length)
                {
                    log.Error(m => m("Response[length:{0}] not equal Actual Send Response[Length:{1}]", responseArr.Length, sendLength));
                }
            }
            catch (Exception ex)
            {
                log.Error(m => m("[State_PurchaseReturn][Handle] Error: {0} \r\n{1}", ex.Message, ex.StackTrace));
            }
            finally
            {
                handler.ServiceState = new State_Exit();
            }
        }
        /// <summary>
        /// 處理邏輯
        /// </summary>
        /// <param name="handler"></param>
        public void Handle(ClientRequestHandler handler)
        {
            try
            {
                POL_Domain request = null;
                bool doMac = true;
                POL_Domain response = null;
                byte[] responseArr = null;
                log.Debug(m => m("[State_PurchaseReturn] {0} Request(ASCII):{1}", handler.ClientSocket.RemoteEndPoint.ToString(), ClientRequestHandler.asciiOctets2String(handler.Request)));
                //1.驗證Mac
                if (this.CheckMac(CheckMacContainer.PRReqMsgUtility, handler.Request))
                {
                    //2.parse request
                    request = this.ParseRequest(CheckMacContainer.PRReqMsgUtility, handler.Request);
                    //3.send to Back-End request and get response
                    response = this.GetResponse(request);
                    if (response == null || string.IsNullOrEmpty(response.PCHR_RC))
                    {
                        //back-End Error
                        response = new POL_Domain()
                        {
                            PCHR_SN = "99999999",
                            PCHR_RC = "990001"
                        };
                    }
                }
                else
                {
                    //MAC驗證失敗
                    doMac = false;
                    response = new POL_Domain()
                    {
                        PCHR_SN = "99999999",
                        PCHR_RC = "990001"
                    };
                }

                //4. parse response byte array(create mac)
                responseArr = this.ParseResponse(CheckMacContainer.PRRespMsgUtility, response, handler.Request, doMac);

                log.Info(m => m("Response(length:{0}):{1}", responseArr.Length, BitConverter.ToString(responseArr).Replace("-", "")));
                int sendLength = handler.ClientSocket.Send(responseArr);
                if (sendLength != responseArr.Length)
                {
                    log.Error(m => m("Response[length:{0}] not equal Actual Send Response[Length:{1}]", responseArr.Length, sendLength));
                }
            }
            catch (Exception ex)
            {
                log.Error(m => m("[State_PurchaseReturn][Handle] Error: {0} \r\n{1}", ex.Message, ex.StackTrace));
            }
            finally
            {
                handler.ServiceState = new State_Exit();
            }
        }
        /// <summary>
        /// 送到後台的request物件並取回response物件
        /// </summary>
        /// <param name="request">request poco</param>
        /// <returns>response poco</returns>
        protected virtual POL_Domain GetResponse(POL_Domain request)
        {
            POL_Domain         result         = null;
            HttpClient         client         = null;
            HttpRequestMessage requestMsg     = null;
            string             requestJSONstr = string.Empty;
            string             jsonData       = string.Empty;

            try
            {
                System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
                requestJSONstr = Newtonsoft.Json.JsonConvert.SerializeObject(request);
                log.Debug(m => m("5.[PurchaseReturn][Send] to Back-End Data: {0}", requestJSONstr));

                string url = ConfigLoader.GetSetting(ConType.PurchaseReturn);
                timer.Start();
                client = new HttpClient()
                {
                    Timeout = new TimeSpan(0, 0, 0, 0, State_PurchaseReturn.ResponseTimeout)
                };
                requestMsg = new HttpRequestMessage(HttpMethod.Post, url);
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                requestMsg.Content = new StringContent(requestJSONstr, Encoding.UTF8, "application/json");
                client.SendAsync(requestMsg).ContinueWith(responseTask =>
                {
                    HttpResponseMessage response = responseTask.Result as HttpResponseMessage;
                    return(response.Content.ReadAsByteArrayAsync().Result);
                }).ContinueWith(dataTask =>
                {
                    byte[] data = dataTask.Result as byte[];
                    jsonData    = Encoding.UTF8.GetString(data);
                    result      = Newtonsoft.Json.JsonConvert.DeserializeObject <POL_Domain>(jsonData);
                }).Wait(State_PurchaseReturn.ResponseTimeout);
                timer.Stop();
                log.Debug(m => m("6.[PurchaseReturn][Receive]Back-End Response(TimeSpend:{1}ms): {0}", jsonData, timer.ElapsedMilliseconds));


                return(result);
            }
            catch (Exception ex)
            {
                log.Error("[GetResponse]Send Back-End Error: " + ex.Message + " \r\n" + ex.StackTrace);
                return(null);
            }
        }
        /// <summary>
        /// Response物件建立MAC並依據規格書轉換成byte[]
        /// </summary>
        /// <param name="msgUtility">Response Msg Parser</param>
        /// <param name="response">後端給的POCO</param>
        /// <param name="request">Origin Request byte array</param>
        /// <param name="doMAC">是否產生MAC:驗證失敗就使用來源的mac</param>
        /// <returns>response byte array</returns>
        protected virtual byte[] ParseResponse(IMsgUtility msgUtility, POL_Domain response, byte[] request, bool doMAC = true)
        {
            log.Debug(m => m("7.轉換後台Response物件並建立MAC並轉成Response Byte[]"));
            byte[] rspResult = new byte[request.Length];
            Buffer.BlockCopy(request, 0, rspResult, 0, request.Length);//

            // modify request to response
            msgUtility.SetStr("02", rspResult, "Communicate");
            msgUtility.SetStr(response.PCHR_RC, rspResult, "ReturnCode");
            msgUtility.SetStr(response.PCHR_SN, rspResult, "CenterSeqNo");
            msgUtility.SetStr(this.amount, rspResult, "Amount");

            msgUtility.SetStr(this.transDateTime, rspResult, "TransDateTime");
            //是否產生mac
            if (doMAC)
            {
                // fetch sha1 data
                this.SetMAC(msgUtility, rspResult, this.readerId, this.transDateTime);
            }
            else
            {
                //若Mac驗證失敗,則使用來源mac簡易回傳
                msgUtility.SetStr(this.mac, rspResult, "Mac");
            }
            // padding data
            this.SetPadding(msgUtility, rspResult);
            return rspResult;
        }
        /// <summary>
        /// Request依據規格書截取需要的資料轉成POCO
        /// </summary>
        /// <param name="msgUtility">Request Msg Parser</param>
        /// <param name="msgBytes">Origin Request byte array</param>
        /// <returns>POCO</returns>
        protected virtual POL_Domain ParseRequest(IMsgUtility msgUtility, byte[] msgBytes)
        {
            log.Debug("3.開始轉換購貨取消Request物件");
            POL_Domain oLDomain = new POL_Domain();
            //ComType:0332
            oLDomain.COM_TYPE = msgUtility.GetStr(msgBytes, "ReqType");

            oLDomain.POS_FLG = msgUtility.GetStr(msgBytes, "ReaderType");

            oLDomain.READER_ID = this.readerId;//CheckMacContainer.AOLReqMsgUtility.GetStr(msgBytes, "ReaderId").Substring(0, 16);

            oLDomain.MERC_FLG = msgUtility.GetStr(msgBytes, "MercFlg");

            oLDomain.STORE_NO = msgUtility.GetStr(msgBytes, "StoreNo");

            oLDomain.REG_ID = msgUtility.GetStr(msgBytes, "RegId");

            // modify StoreNo and RegId
            if ("SET".Equals(oLDomain.MERC_FLG))
            {
                oLDomain.STORE_NO = oLDomain.STORE_NO.Substring(2, 6);
                oLDomain.REG_ID = oLDomain.REG_ID.Substring(1, 2);
            }

            //
            oLDomain.PCHR_AMT = Convert.ToInt32(this.amount);
            //
            oLDomain.ICC_NO = msgUtility.GetStr(msgBytes, "CardNo");

            log.Debug("4.結束轉換購貨取消Request物件");
            return oLDomain;
        }
        /// <summary>
        /// 送到後台的request物件並取回response物件
        /// </summary>
        /// <param name="request">request poco</param>
        /// <returns>response poco</returns>
        protected virtual POL_Domain GetResponse(POL_Domain request)
        {
            POL_Domain result = null;
            HttpClient client = null;
            HttpRequestMessage requestMsg = null;
            string requestJSONstr = string.Empty;
            string jsonData = string.Empty;
            try
            {
                System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
                requestJSONstr = Newtonsoft.Json.JsonConvert.SerializeObject(request);
                log.Debug(m => m("5.[PurchaseReturn][Send] to Back-End Data: {0}", requestJSONstr));

                string url = ConfigLoader.GetSetting(ConType.PurchaseReturn);
                timer.Start();
                client = new HttpClient() { Timeout = new TimeSpan(0, 0, 0, 0, State_PurchaseReturn.ResponseTimeout) };
                requestMsg = new HttpRequestMessage(HttpMethod.Post, url);
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                requestMsg.Content = new StringContent(requestJSONstr, Encoding.UTF8, "application/json");
                client.SendAsync(requestMsg).ContinueWith(responseTask =>
                {
                    HttpResponseMessage response = responseTask.Result as HttpResponseMessage;
                    return response.Content.ReadAsByteArrayAsync().Result;
                }).ContinueWith(dataTask =>
                {
                    byte[] data = dataTask.Result as byte[];
                    jsonData = Encoding.UTF8.GetString(data);
                    result = Newtonsoft.Json.JsonConvert.DeserializeObject<POL_Domain>(jsonData);
                }).Wait(State_PurchaseReturn.ResponseTimeout);
                timer.Stop();
                log.Debug(m => m("6.[PurchaseReturn][Receive]Back-End Response(TimeSpend:{1}ms): {0}", jsonData, timer.ElapsedMilliseconds));

                return result;
            }
            catch (Exception ex)
            {
                log.Error("[GetResponse]Send Back-End Error: " + ex.Message + " \r\n" + ex.StackTrace);
                return null;
            }
        }