using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;

namespace DeviceRepair.Utils
{
    public static class ObjectExtend
    {
        /// <summary>
        /// 对比两个对象并获取差异
        /// </summary>
        /// <param name="t1">比较的对象</param>
        /// <param name="t2">比较的对象2,字典集合的值将会为该对象中的值</param>
        /// <returns></returns>
        public static Dictionary<string, object> GetDifferencesColumn(this object t1, object t2)
        {
            if (t1.GetType() != t2.GetType())
                throw new ArgumentException("实体对象必须是相同的.");

            var differences = new Dictionary<string, object>();
            var properties = t1.GetType().GetProperties();

            foreach (var prop in properties)
            {
                var value1 = prop.GetValue(t1);
                var value2 = prop.GetValue(t2);

                if (!Equals(value1, value2))
                {
                    differences.Add(prop.Name, value2);
                }
            }

            return differences;
        }

        /// <summary>
        /// 获取对象中不同的值,取出赋值到新对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t1"></param>
        /// <param name="t2"></param>
        /// <returns></returns>
        public static T GetDifferencesModel<T>(this T t1, T t2) where T : class
        {

            PropertyInfo[] properties = typeof(T).GetProperties();
            T newObj = Activator.CreateInstance<T>();

            foreach (PropertyInfo property in properties)
            {
                object value1 = property.GetValue(t1);
                object value2 = property.GetValue(t2);

                if (!Equals(value1, value2)) // 判断两个值是否相等
                {
                    property.SetValue(newObj, value2); // 将不同的值设置到新对象中
                }
            }

            return newObj;
        }

        /// <summary>
        /// 数据集转键值对
        /// </summary>
        /// <param name="byteArray"></param>
        /// <returns></returns>
        public static Dictionary<string, object> toDictionary(this byte[] byteArray)
        {
            Dictionary<string, object> deserializedDictionary;
            using (MemoryStream memoryStream = new MemoryStream(byteArray))
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                deserializedDictionary = (Dictionary<string, object>)binaryFormatter.Deserialize(memoryStream);
            }
            return deserializedDictionary;
        }

        public static T ToObject<T>(this byte[] byteArray)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream(byteArray))
            {
                object obj = formatter.Deserialize(stream);
                return (T)obj;
            }
        }

        /// <summary>
        /// 赋值对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        public static void Copy<T>(object source, object destination)
        {
            var properties = typeof(T).GetProperties();

            foreach (var property in properties)
            {
                if (property.CanRead && property.CanWrite)
                {
                    var value = property.GetValue(source);
                    property.SetValue(destination, value);
                }
            }
        }

        public static void CopyPropertiesTo<T>(this T source, T target)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            if (target == null)
                throw new ArgumentNullException(nameof(target));

            PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (PropertyInfo property in properties)
            {
                if (property.CanWrite)
                {
                    property.SetValue(target, property.GetValue(source), null);
                }
            }
        }

        /// <summary>
        /// 反射实现两个类的对象之间相同属性的值的复制
        /// 适用于初始化新实体
        /// </summary>
        /// <typeparam name="D">返回的实体</typeparam>
        /// <typeparam name="S">数据源实体</typeparam>
        /// <param name="s">数据源实体</param>
        /// <returns>返回的新实体</returns>
        public static D Mapper<D, S>(S s)
        {
            D d = Activator.CreateInstance<D>(); //构造新实例
            try
            {
                var Types = s.GetType();//获得类型  
                var Typed = typeof(D);
                foreach (PropertyInfo sp in Types.GetProperties())//获得类型的属性字段  
                {
                    foreach (PropertyInfo dp in Typed.GetProperties())
                    {
                        if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType && dp.Name != "Error" && dp.Name != "Item")//判断属性名是否相同  
                        {
                            dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性  
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return d;
        }
    }
}
