using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace DirectService.Tools
{
    public class ObjectHelper
    {
        /// <summary>
        /// 深度复制
        /// </summary>
        public static T DeepCopy<T>(T obj)
        {
            return Copy(obj, true);
        }
        /// <summary>
        /// 浅复制
        /// </summary>
        public static T ShallowCopy<T>(T obj)
        {
            return Copy(obj);
        }

        private static T Copy<T>(T obj, bool deep = false)
        {
            //如果是字符串或值类型则直接返回
            if (obj == null || obj.GetType().IsValueType || obj is string)
            {
                return obj;
            }
            object retval = Activator.CreateInstance(obj.GetType());

            if (obj is IDictionary)
            {
                var oriDic = obj as IDictionary;
                var newDic = retval as IDictionary;
                var enumerator = oriDic.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    newDic.Add(enumerator.Key, enumerator.Value);
                }
            }
            else if (obj is IList)
            {
                var oriList = obj as IList;
                var newList = retval as IList;
                foreach (var item in oriList)
                {
                    newList.Add(item);
                }
            }
            else
            {
                var fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).ToList();
                var type = obj.GetType();
                while ((type = type.BaseType) != typeof(object))
                {
                    fields.AddRange(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance));
                }
                foreach (FieldInfo field in fields)
                {
                    if (field.IsLiteral)
                    {
                        continue;
                    }
                    try
                    {
                        var value = field.GetValue(obj);
                        if (deep)
                        {
                            value = Copy(value, true);
                        }
                        field.SetValue(retval, value);
                    }
                    catch (Exception ex)
                    {
                        Trace.Write(string.Format("{0}\r\n属性:{1}\r\n异常:{2}", obj.GetType().FullName, field.Name, ex));
                    }
                }
            }
            return (T)retval;
        }
    }
}
