using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Newtonsoft.Json.Linq;

namespace PushPlatform.Common.Util
{
    public static class ObjectUtil
    {
        public static object Clone(this object obj)
        {
            MemoryStream stream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, obj);
            stream.Position = 0;
            return formatter.Deserialize(stream);
        }

        public static T Clone<T>(this T obj)
        {
            using (Stream objectStream = new MemoryStream())
            {
                //利用 System.Runtime.Serialization序列化与反序列化完成引用对象的复制  
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, obj);
                objectStream.Seek(0, SeekOrigin.Begin);
                return (T)formatter.Deserialize(objectStream);
            }
        }

        public static void CopyPropertys(object source, object target)
        {
            var sPropertys = source.GetType().GetProperties();
            foreach (var sp in sPropertys)
            {
                var name = sp.Name;
                //if (name == "CreateTime" || name == "UpdateTime" || name == "UpdateUser" || name == "CreateUser")
                //{
                //    continue;
                //}
                var tp = target.GetType().GetProperty(name);
                if (tp == null || !tp.CanWrite)
                {
                    continue;
                }
                else
                {
                    tp.SetValue(target, sp.GetValue(source, null), null);
                }
            }
        }

        public static void SetPropertyValue(object obj, string propertyName, object value)
        {
            var sProperty = obj.GetType().GetProperty(propertyName);
            if (sProperty != null)
            {
                object nr = value;
                var nrType = sProperty.PropertyType;
                if (nrType == typeof(decimal) || nrType == typeof(decimal?))
                {
                    nr = Convert.ToDecimal(nr);
                }
                else if (nrType == typeof(Int64) || nrType == typeof(Int64?))
                {
                    nr = Convert.ToInt64(nr);
                }
                else if (nrType == typeof(double) || nrType == typeof(double?))
                {
                    nr = Convert.ToDouble(nr);
                }
                else if (nrType == typeof(Int32) || nrType == typeof(Int32?))
                {
                    nr = Convert.ToInt32(nr);
                }
                else if (nrType == typeof(Int16) || nrType == typeof(Int16?))
                {
                    nr = Convert.ToInt16(nr);
                }
                else if (nrType == typeof(DateTime) || nrType == typeof(DateTime?))
                {
                    try
                    {
                        nr = Convert.ToDateTime(nr);
                    }
                    catch
                    {
                        nr = null;
                    }
                }
                sProperty.SetValue(obj, nr, null);
            }
        }

        public static bool Equals(object obj1, object obj2)
        {
            if (obj1 == null || obj2 == null)
            {
                return false;
            }
            if (!obj1.GetType().Equals(obj2.GetType()))
            {
                return false;
            }
            var ps1 = obj1.GetType().GetProperties();
            List<Type> basicType = new List<Type>(){
                typeof(long),
                typeof(long?),
                typeof(bool),
                typeof(bool?),
                typeof(string),
                typeof(DateTime),
                typeof(DateTime?),
                typeof(decimal),
                typeof(decimal?),
                typeof(double),
                typeof(double?),
                typeof(int),
                typeof(int?),
                typeof(float),
                typeof(float?),
                typeof(short),
                typeof(short?),
                typeof(Guid),
                typeof(Guid?)
            };
            foreach (var c in ps1)
            {
                if (!basicType.Any(x => x == c.PropertyType))
                {
                    continue;
                }
                var pname = c.Name;
                var lname = pname.ToLower();
                if (lname == "CreateTime" || lname == "UpdateTime" || lname == "UpdateUser" || lname == "CreateUser")
                {
                    continue;
                }
                var value1 = c.GetValue(obj1, null);
                var value2 = obj2.GetType().GetProperty(pname).GetValue(obj2, null);
                if (value1 == null && value2 == null)
                {
                    continue;
                }
                if (value1 != null)
                {
                    if (!value1.Equals(value2))
                    {
                        return false;
                    }
                }
                else if (value2 != null)
                {
                    if (!value2.Equals(value1))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public static void PropertysUrlDecode(object obj)
        {
            var sPropertys = obj.GetType().GetProperties();
            foreach (var sp in sPropertys)
            {
                if (sp.PropertyType == typeof(string))
                {
                    var value = (string)sp.GetValue(obj, null);
                    sp.SetValue(obj, HttpUtility.UrlDecode(value), null);
                }
            }
        }


        public static T GetValue<T>(this JObject jObject, string paramterName)
        {
            JToken token;
            if (jObject.TryGetValue(paramterName, out token))
            {
                return token.Value<T>();
            }
            else
            {
                return default(T);
            }
        }
    }
}
