/*
 * 由SharpDevelop创建。
 * 用户： 吴隆健
 * 日期: 2018-04-02
 * 时间: 10:55
 * 
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */
using System;
using Newtonsoft.Json;
using System.Text;
using System.Security.Cryptography;

namespace GameData
{


    /// <summary>
    /// Description of JsonPack.
    /// </summary>
    public static class JsonPack
    {
        /// <summary>
        /// 秘钥
        /// </summary>
        public const string key = "asnfkjahsfjabnslkd";

        /// <summary>
        /// JSon 序列化是否包含默认值
        /// </summary>
        public static bool IsHaveDefault = true;

        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string ENCRYMD5(string text)
        {
            byte[] data = Encoding.UTF8.GetBytes(text);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] output = md5.ComputeHash(data);
            return BitConverter.ToString(output).Replace("-", "");
        }

        /// <summary>
        /// 获取Json数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string GetJson(Object data)
        {
            JsonSerializerSettings jsonset = new JsonSerializerSettings();
            jsonset.DefaultValueHandling = DefaultValueHandling.Ignore;
            return IsHaveDefault ? JsonConvert.SerializeObject(data, jsonset) : JsonConvert.SerializeObject(data);
        }
        
        /// <summary>
        /// 获取Json数据
        /// </summary>
        /// <param name="data"></param>
        /// <param name="jsonSet"></param>
        /// <returns></returns>
        public static string GetJson(Object data, JsonSerializerSettings jsonSet)
        {
            return IsHaveDefault ? JsonConvert.SerializeObject(data, jsonSet) : JsonConvert.SerializeObject(data);
        }

        public static string GetJsonNoIgnore(Object data) {
            return JsonConvert.SerializeObject(data);
        }

        /// <summary>
        /// 获取数据
        /// </summary>
        /// <param name="jsonData"></param>
        /// <returns></returns>
        public static T GetData<T>(string jsonData)
        {
            // JsonSerializerSettings jsonset = new JsonSerializerSettings();
            // jsonset.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
#pragma warning disable CS0168 // 声明了变量，但从未使用过
            try
            {
                return JsonConvert.DeserializeObject<T>(jsonData);
            }
            catch (Exception e)
            {
                return default(T);
            }
#pragma warning restore CS0168 // 声明了变量，但从未使用过
        }
        
        public static T GetData<T>(string jsonData, JsonSerializerSettings jsonSet)
        {
#pragma warning disable CS0168 // 声明了变量，但从未使用过
            try
            {
                return JsonConvert.DeserializeObject<T>(jsonData, jsonSet);
            }
            catch (Exception e)
            {
                return default(T);
            }
#pragma warning restore CS0168 // 声明了变量，但从未使用过
        }

        /// <summary>
        /// 获取包裹的json数据
        /// </summary>
        /// <param name="head">包头</param>
        /// <param name="data">数据</param>
        /// <param name="md5">md5</param>
        /// <returns></returns>
        public static string GetJsonByPack<T>(T head, System.Object data, bool md5 = false) where T : PackHead
        {

            string jsonHead = string.Empty, jsondata = string.Empty;

            if (head != null)
                jsonHead = GetJson(head);

            if (data != null)
                jsondata = GetJson(data);

            string msg = jsonHead + jsondata;

            int headlen = jsonHead.Length;
            int datalen = jsondata.Length;

            if (md5)
            {

                string encryStr = msg;
                if (head.clientVer > 1)
                    encryStr = encryStr + key;
                if (msg != null)
                    msg += ENCRYMD5(encryStr);

                datalen += 32;
            }

            return IntToStr16(jsonHead.Length) + IntToStr16(jsondata.Length) + msg;
        }

        /// <summary>
        /// 获取包裹的json数据
        /// </summary>
        /// <param name="head">包头</param>
        /// <param name="messagedata">数据</param>
        /// <param name="md5">md5</param>
        /// <returns></returns>
        public static string GetJsonByPack_head<T>(T head, string messagedata, bool md5 = false) where T : PackHead
        {
            string jsonHead = string.Empty;
            string jsondata = messagedata;
            if (head != null)
                jsonHead = GetJson(head);
            if (jsondata == null)
                jsondata = string.Empty;

            string msg = jsonHead + jsondata;

            int headlen = jsonHead.Length;
            int datalen = jsondata.Length;

            if (md5)
            {
                string encryStr = msg;
                if (head.clientVer > 1)
                    encryStr = encryStr + key;
                if (msg != null)
                    msg += ENCRYMD5(encryStr);

                datalen += 32;
            }

            return IntToStr16(jsonHead.Length) + IntToStr16(jsondata.Length) + msg;
        }

        /// <summary>
        /// 获取包裹的json数据base64字符串类型
        /// </summary>
        /// <param name="head">包头数据</param>
        /// <param name="data">包数据</param>
        /// <param name="md5">md5加签</param>
        /// <returns></returns>
        public static string GetJsonByPackBase64<T>(T head, System.Object data, bool md5 = false) where T : PackHead
        {
            string str = GetJsonByPack(head, data, md5);
            return GetBase64(str);
        }

        /// <summary>
        /// 获取报复哦的json数据base64字符串类型
        /// </summary>
        /// <param name="head">包头数据</param>
        /// <param name="messagedata">包数据</param>
        /// <param name="md5">md5加签</param>
        /// <returns></returns>
        public static string GetJsonByPackBase64_head<T>(T head, string messagedata, bool md5 = false) where T : PackHead
        {
            string str = GetJsonByPack_head(head, messagedata, md5);
            return GetBase64(str);
        }

        /// <summary>
        /// 转换成base64
        /// </summary>
        /// <param name="jsonpack"></param>
        /// <returns></returns>
        public static string GetBase64(string jsonpack)
        {
            byte[] data = System.Text.Encoding.UTF8.GetBytes(jsonpack);
            return Convert.ToBase64String(data);
        }

        /// <summary>
        /// 把base64转换成普通字符串
        /// </summary>
        /// <param name="jsonpack64"></param>
        /// <returns></returns>
        public static string GetStringByBase64(string jsonpack64)
        {
            byte[] data = Convert.FromBase64String(jsonpack64);
            return System.Text.Encoding.UTF8.GetString(data);
        }

        private static bool CheckMD5(string jsondata, bool isCheck)
        {

            if (!isCheck)
                return true;

            if (jsondata == null || jsondata.Length < 48)
                return false;

            int len = jsondata.Length;
            int idx = len - 32;
            string md5str = jsondata.Substring(idx);
            string datastr = jsondata.Substring(0, len - 32);
            datastr = datastr.Substring(16);

            if (md5str == null)
                return false;

            datastr += key;

            string newmd5str = ENCRYMD5(datastr).ToLower();

            return md5str.ToLower() == newmd5str;
        }

        /// <summary>
        /// 获取json的包数据
        /// </summary>
        /// <param name="jsonstring">json字符串</param>
        /// <param name="head">包头数据</param>
        /// <param name="data">包数据</param>
        /// <param name="md5">是否md5验证</param>
        /// <returns>是否验证通过</returns>
        public static bool GetPackByJson<T, K>(string jsonstring, out K head, out T data, bool md5 = false) where K : PackHead
        {
            int startIdx = 0;
            int len = 8;
            string len1 = jsonstring.Substring(startIdx, len);//包头长度
            startIdx += len;
            string len2 = jsonstring.Substring(startIdx, len);//包数据长度
            startIdx += len;
            len = Str16ToInt(len1);

            head = GetData<K>(jsonstring.Substring(startIdx, len));

            startIdx += len;
            len = Str16ToInt(len2);

            data = GetData<T>(jsonstring.Substring(startIdx, len));

            startIdx += len;

            if (md5)
            {
                return CheckMD5(jsonstring, head.clientVer > 1);
            }
            return true;
        }

        /// <summary>
        /// 获取json数据包
        /// </summary>
        /// <param name="jsonstring">base64json字符创</param>
        /// <param name="head">包头</param>
        /// <param name="data">包数据</param>
        /// <param name="md5">是否md5验证</param>
        public static bool GetPackByJsonBase64<T, K>(string jsonstring, out K head, out T data, bool md5 = false) where K : PackHead
        {
            jsonstring = GetStringByBase64(jsonstring);
            return GetPackByJson<T, K>(jsonstring, out head, out data, md5);
        }


        /// <summary>
        /// 获取包数据
        /// </summary>
        /// <returns>包数据</returns>
        /// <param name="jsonstring">json字符串</param>
        /// <typeparam name="T">获取的包数据类型</typeparam>
        public static T GetPackData<T>(string jsonstring)
        {
            return GetData<T>(jsonstring);
        }

        /// <summary>
        /// 字符转Ushort数据
        /// </summary>
        /// <param name="strs"></param>
        /// <returns></returns>
        public static int Str16ToInt(string strs)
        {
            return Convert.ToInt32(strs, 16);
        }

        /// <summary>
        /// 把int转成16进制字符串
        /// </summary>
        /// <returns></returns>
        public static string IntToStr16(int num)
        {
            string str16 = Convert.ToString(num, 16);
            string tmp = "";
            for (int i = str16.Length; i < 8; i++)
            {
                tmp += "0";
            }
            return tmp + str16;
        }

        /// <summary>
        /// 获取包头
        /// </summary>
        /// <param name="jsonpack">包体</param>
        /// <param name="head">包头</param>
        /// <param name="md5">是否md5验证</param>
        public static string GetPackBase64Head<T>(string jsonpack, out T head, bool md5 = false) where T : PackHead
        {

            jsonpack = GetStringByBase64(jsonpack);

            int startIdx = 0;
            int len = 8;
            string len1 = jsonpack.Substring(startIdx, len);//包头长度
            startIdx += len;
            string len2 = jsonpack.Substring(startIdx, len);//包数据长度
            startIdx += len;
            len = Str16ToInt(len1);

            head = GetData<T>(jsonpack.Substring(startIdx, len));

            startIdx += len;
            len = Str16ToInt(len2);

            if (md5)
            {
                if (!CheckMD5(jsonpack, head.clientVer > 1))
                    return null;
            }

            return jsonpack.Substring(startIdx, len);
        }

        /// <summary>
        /// 获取包头
        /// </summary>
        /// <param name="jsonpack"></param>
        /// <param name="head"></param>
        /// <param name="md5"></param>
        /// <returns></returns>
        public static string GetPackHead<T>(string jsonpack, out T head, bool md5 = false) where T : PackHead
        {
            int startIdx = 0;
            int len = 8;
            string len1 = jsonpack.Substring(startIdx, len);//包头长度
            startIdx += len;
            string len2 = jsonpack.Substring(startIdx, len);//包数据长度
            startIdx += len;
            len = Str16ToInt(len1);

            head = GetData<T>(jsonpack.Substring(startIdx, len));

            startIdx += len;
            len = Str16ToInt(len2);

            if (md5)
            {
                if (!CheckMD5(jsonpack, head.clientVer > 1))
                    return null;
            }

            return jsonpack.Substring(startIdx, len);
        }
    }
}