using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Platform.Common;
using Platform.ServiceProxy.ServiceHelper;
using Platform.Common.RunningParameters;
using Platform.Common.LogSystem;
using TellerSystem.ServiceProxy.Ext;
using TellerSystem.ServiceProxy.Ext.ServiceHelper;
using System.Diagnostics;
using TellerSystem.Communication.SocketListener;
using System.IO;

namespace TellerSystem.Communication.Package
{
    /// <summary>
    /// 交易处理相关操作
    /// </summary>
    class MsgPackage
    {
        //报文处理接口对象
        public static Dictionary<PackageType, IPackage> PackageList = new Dictionary<PackageType, IPackage>
        {
            {PackageType.Msg858301,Msg858301.GetInstance()},
            {PackageType.Msg858302,Msg858302.GetInstance()},
             {PackageType.Msg858304,Msg858304.GetInstance()},
             {PackageType.MsgXml01,MsgXml01.GetInstance()}
        };

        /// <summary>
        /// 交易处理
        /// </summary>
        /// <param name="msg">报文对象</param>
        /// <param name="transit">callserver,callagn,calltips</param>
        /// <returns></returns>
        public static bool Trade(Message msg, PackageType packageType, string transit)
        {
            //组包后数据
            byte[] integrateData;
            //交易整体数据
            byte[] totalData;
            //通讯返回数据
            byte[] returnData;
            byte[] fileData = new byte[0];
            bool retunValue = false;

            //根据当前报文类型实例化报文处理对象
            if (!PackageList.ContainsKey(packageType))
            {
                PlatformLogger.TradeErrorInfo("MsgPackage.Trade:不支持的报文类型！-->" + packageType.ToString(), null);
                return false;
            }
            try
            {
                //根据当前报文类型实例化报文处理对象，
                var package = PackageList[packageType];
                //GetPackageInstance(transit);
                //组包
                integrateData = package.Integrate(msg);
                //通讯
                var fileName = msg.Fd3.Replace(" ", "") + msg.Fd10.Replace(" ", "");
                Stopwatch watch = new Stopwatch();
                watch.Start();
                List<byte[]> list;
                if (ServiceSettings.IsRecordPrintData)
                {
                    //登记通讯报文类型
                    string msgType = msg.IsMainTrade ? packageType.ToString() : string.Empty;
                    try
                    {
                        list = TradeHandle.DoTrade(transit, integrateData, msg.Fd3, fileName, PlatformSettings.Encoding.GetBytes(Message.Cconv(msg.FileData)), null, msg.SerialNumber, msgType);//生僻字转义：文件组包处理
                    }
                    catch { list = null; }
                    //当主交易通讯情况，未返回数据，需要查询记录，尝试进行补偿
                    if (msg.IsMainTrade && (list == null || list.Count == 0))
                    {
                        //考虑到网络波动，需尝试3次
                        for (int i = 0; i < 3; i++)
                        {
                            try
                            {
                                var data = PrintManagerHandle.GetPrintExtDataById(msg.SerialNumber);
                                if (data != null)
                                {
                                    PlatformLogger.SystemInfo("MsgPackage:主通讯补偿成功！" + msg.SerialNumber);
                                    list = new List<byte[]> { data.Message };
                                    if (data.MsgFile != null && data.MsgFile.Length > 0) list.Add(data.MsgFile);
                                    break;
                                }
                            }
                            catch (Exception ex) { PlatformLogger.SystemErrorInfo("MsgPackage:主通讯补偿失败！" + msg.SerialNumber, ex); }
                            System.Threading.Thread.Sleep(200);
                        }
                        //登记入库
                        TradeHandle.WriteImportantLog("主通讯触发补偿", msg.SerialNumber, ((list != null && list.Count > 0) ? "成功" : "失败"), "DoTrade", "2", string.Join(",", SocketManager.GetLocalIpAddressList()));
                    }
                }
                else
                {
                    list = TradeHandle.DoTrade(transit, integrateData, msg.Fd3, fileName, PlatformSettings.Encoding.GetBytes(Message.Cconv(msg.FileData)), null, msg.SerialNumber);
                }
                watch.Stop();
                if (watch.ElapsedMilliseconds > 2000)
                    TradeHandle.WriteImportantLog("通讯时间统计", watch.ElapsedMilliseconds.ToString(), msg.Fd16, "DoTrade", "2", string.Join(",", SocketManager.GetLocalIpAddressList()));
                //重置主交易标识
                msg.IsMainTrade = false;
                returnData = list[0];
                //处理文件附件
                if (list.Count > 1)
                {
                    fileData = list[1];
                }
                byte fileDataFlag = 0;
                if (returnData != null && returnData.Length > 0)
                {
                    if (returnData.Length < 20)
                        PlatformLogger.SystemErrorInfo(string.Format("MsgPackage:返回报文长度太短，无法获取附件标志！", returnData.Length), new Exception());
                    fileDataFlag = returnData[20];
                }
                else
                {
                    //通讯出现异常，需要添加错误码
                    msg.Fd12 = "COMM";
                    return false;
                }
                //重置附件发送标志
                msg.FileFlag = false;
                totalData = new byte[returnData.Length + fileData.Length];
                Array.Copy(returnData, 0, totalData, 0, returnData.Length);
                Array.Copy(fileData, 0, totalData, returnData.Length, fileData.Length);
                //解包
                retunValue = package.Analyze(msg, totalData);


            }
            catch (Exception ex)
            {
                //写错误信息
                PlatformLogger.SystemErrorInfo("Trade: 函数出错. ", ex);
                return false;
            }
            return retunValue;
        }

        #region 报文处理相关功能函数

        /// <summary>
        /// 加密，解密函数
        /// 加密：flg=1    解密：flg=0
        /// </summary>
        /// <param name="myData"></param>
        /// <param name="key"></param>
        /// <param name="flg"></param>
        /// <returns></returns>
        public static bool Encrypt(byte[] myData, byte[] key, int flg)
        {
            //TODO:焦作项目不用做数据加密,暂时写死
            if (true) return true;

            int klen;
            klen = key.Length;
            string value;
            try
            {
                for (int i = 0; i < myData.Length; i++)
                {
                    //加密
                    if (flg == 1)
                    {   //溢出情况           
                        if ((myData[i] + key[i % klen]) > 255)
                        {
                            value = Convert.ToString((myData[i]) + key[i % klen], 2);
                            myData[i] = Convert.ToByte(Convert.ToInt32(value.Substring(value.Length - 8, 8), 2));
                        }
                        //正常情况
                        else
                        {
                            myData[i] = Convert.ToByte(myData[i] + key[i % klen]);
                        }
                    }
                    //解密
                    else
                    {
                        //溢出情况
                        if (myData[i] < key[i % klen])
                        {
                            value = Convert.ToString((myData[i]), 2).PadLeft(8, '0');
                            value = "1" + value;
                            myData[i] = Convert.ToByte(Convert.ToInt32(value, 2) - key[i % klen]);
                        }
                        //正常情况
                        else
                        {
                            myData[i] = Convert.ToByte(myData[i] - key[i % klen]);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //写错误信息
                PlatformLogger.SystemErrorInfo("加密解密出错！", ex);
                throw;
            }
            return true;
        }

        /// <summary>
        /// 复制对象的属性值
        /// </summary>
        /// <param name="obj">复制目标对象</param>
        /// <param name="source">复制源对象</param>
        public static void Clone(Message obj, Message source)
        {
            System.Reflection.PropertyInfo[] tmp = obj.GetType().GetProperties();

            //复制所有的属性
            for (int i = 0; i < tmp.Length; i++)
            {
                tmp[i].SetValue(obj, tmp[i].GetValue(source, null), null);
            }
            //复制所有的filed
        }


        /// <summary>
        /// 字节数组修复为GDK编码规则
        /// </summary>
        /// <param name="data"></param>
        public static void CheckByte(byte[] data)
        {
            byte[] tmpData = null;
            string tmpStr = string.Empty;
            if (data == null || data.Length == 0)
                return;
            for (int i = 0; i < data.Length; i++)
            {
                //如果是ascii码字符,直接跳过 
                if (data[i] < 128)
                    continue;
                //added by liuyong 2010-4-16 start
                else
                {
                    if ((i + 1) >= data.Length)
                        continue;
                    tmpData = new byte[2];
                    tmpData[0] = data[i];
                    tmpData[1] = data[i + 1];

                    tmpStr = PlatformSettings.Encoding.GetString(tmpData);
                    //全角字符且不是汉字则不进行转换
                    if (IsSbc(tmpStr) && !IsChinese(tmpStr))
                    {
                        i++;
                        continue;
                    }
                }
                //added by liuyong 2010-4-16 end
                if (data[i] >= 0x81 && data[i] <= 0xa0)//GBK/3高位区间 129-160
                {
                    if ((i + 1) >= data.Length)
                        continue;
                    if (data[i + 1] < 0x40 || data[i + 1] > 0xfe)  //64 254
                    {
                        data[i] = 61;
                        continue;
                    }
                    i++;
                }
                else if (data[i] >= 0xa1 && data[i] <= 0xa9)//GBK/1 高位区间 161-169
                {
                    if ((i + 1) >= data.Length)
                        continue;
                    if (data[i + 1] < 0xa1 || data[i + 1] > 0xef)  //161 239
                    {
                        data[i] = 61;
                        continue;
                    }
                    i++;
                }
                else if (data[i] >= 0xaa && data[i] <= 0xfe)//GBK/4高位区间  170-254
                {
                    if ((i + 1) >= data.Length)
                        continue;
                    if (data[i + 1] < 0x40) //64
                    {
                        data[i] = 61;
                        continue;
                    }
                    else if (data[i + 1] > 0xa0) //160
                    {
                        //GBK/2高位区间
                        if ((data[i] >= 0xb0 && data[i] <= 0xf7)) //176-247
                        {
                            //低位错误，证明是随机字符，高低位同时修复161 254
                            if (data[i + 1] < 0xa1 || data[i + 1] > 0xfe)
                            {
                                data[i] = 61;
                                continue;
                            }
                        }
                    }
                    i++;
                }
                else //错误乱码直接修复
                {
                    data[i] = 61;
                }
            }
        }

        /// <summary>
        /// 判断字符串是否是全角字符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static bool IsSbc(string str)
        {
            bool blRet = false;
            if (2 * str.Length == Encoding.Default.GetByteCount(str))
            {
                blRet = true;
            }
            else
            {
                blRet = false;
            }
            return blRet;
        }

        /// <summary>
        /// 判断是否为中文
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        private static bool IsChinese(string word)
        {
            Regex rx = null;
            if (string.IsNullOrEmpty(word))
                return false;

            rx = new Regex("^[\u4e00-\u9fa5]$");

            if (rx.IsMatch(word))
                return true;
            else
                return false;
        }

        #endregion

    }
}
