using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace Misc
{
    public static class PropertiesManager
    {

        /// <summary>
        /// 获取所有属性名。
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<string> GetAllPropertyNames(object obj)
        {
            PropertyInfo[] properties = obj.GetType().GetProperties();

            return from p in properties select p.Name;
        }
        /// <summary>
        /// 获取所有属性名。
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<string> GetAllPropertyNames(Type type)
        {
            PropertyInfo[] properties = type.GetProperties();

            return from p in properties select p.Name;
        }
        /// <summary>
        /// 设定参数(属性)的值,触发属性值变化“通知”,writeVal
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName">属性名</param>
        /// <param name="v"></param>
        public static void SetValue(object obj, string propertyName, object v)
        {
            //if (!getRootProperty(ref obj, ref propertyName))
            //    return;
            PropertyInfo property = obj.GetType().GetProperty(propertyName);
            if (property != null)
            {
                property.SetValue(obj, v, null);
            }
        }

        static bool getRootProperty(ref object obj, ref string propertyName) {
            Regex r = new Regex(@"(\S+)\[(\d+)\]");

            string[] lvs = propertyName.Split('.');
            if (lvs.Count() > 1)
            {
                //这个是多级的
                for (int i = 0; i < lvs.Count() - 1; i++)
                {
                    PropertyInfo property;
                    string name = lvs[i];
                    int index = 0;
                    var match = r.Match(name);
                    if (match.Success)
                    {
                        name = match.Groups[1].Value;
                        index = int.Parse(match.Groups[2].Value);
                    }
                    property = obj.GetType().GetProperty(name);
                    if (property == null)
                        return false;//异常
                    if(match.Success)
                        obj = property.GetValue(obj,new object[] { index });
                    else
                        obj = property.GetValue(obj);
                }
                propertyName = lvs.Last();
            }
            return true;
        }
        /// <summary>
        /// 设定参数(属性)的值,触发属性值变化“通知”,writeVal
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <param name="val"></param>
        public static void SetValue(object obj, string propertyName, string val)
        {
            //if (!getRootProperty(ref obj, ref propertyName))
            //    return;

            PropertyInfo property = obj.GetType().GetProperty(propertyName);
            if (property != null)
            {
                object v = Converter.Parse(val, property.PropertyType);
                property.SetValue(obj, v, null);
            }
        }

        /// <summary>
        /// 获取设定的属性值,writeVal
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetValue(object obj, string propertyName)
        {
            //if (!getRootProperty(ref obj, ref propertyName))
            //    return null;

            PropertyInfo property = obj.GetType().GetProperty(propertyName);
            if (property != null)
            {
                return property.GetValue(obj, null);
            }
            else
                return null;
        }


        /// <summary>
        /// 把 src内的全部属性,复制到 dest
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dest"></param>
        public static void CopyTo(object src, object dest)
        {
            Type t = src.GetType();
            if (src.GetType() != dest.GetType())
            {
                throw new Exception("CopyTo src.GetType() != dest.GetType()");
            }

            foreach (PropertyInfo propertyInfo in t.GetProperties())
            {
                //忽略不复制!!!
                if (propertyInfo.GetCustomAttributes(typeof(CopyIgnoreAttribute), false).Count() > 0)
                    continue;

                //ICopiable
                //if (propertyInfo.PropertyType.IsSubclassOf(typeof(ICopiable)))
                if(typeof(ICopiable).IsAssignableFrom(propertyInfo.PropertyType))
                {
                    ICopiable copiable = propertyInfo.GetValue(dest, null) as ICopiable;
                    copiable.Copy(propertyInfo.GetValue(src, null));
                }
                else if(propertyInfo.CanWrite)
                {
                    propertyInfo.SetValue(dest, propertyInfo.GetValue(src, null), null);
                }
            }
        }

        /// <summary>
        /// 检测 dest是否 实现了ICopiable,如果是,调用dest.Copy ;否 调用CopyTo(src,dest)
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dest"></param>
        public static void AutoCopyTo(object src, object dest)
        {
            if (dest is ICopiable)
            {
                ((ICopiable)dest).Copy(src);
            }
            else
            {
                CopyTo(src, dest);
            }
        }

    }

    /// <summary>
    /// 一般情况 用 Misc.PropertiesManager.CopyTo 就能解决问题
    /// 但 只有get的属性,是没法复制的
    /// 只能通过 继承 ICopiable, 解决 只能get 的属性 复制问题
    /// </summary>
    public interface ICopiable
    {
        /// <summary>
        /// 从 src 复制全部数据过来!!!
        /// 
        /// </summary>
        /// <param name="src"></param>
        void Copy(object src);
    }
}