#region COPYRIGHT
//
//     THIS IS GENERATED BY TEMPLATE
//     
//     AUTHOR  :     ROYE
//     DATE       :     2010
//
//     COPYRIGHT (C) 2010, TIANXIAHOTEL TECHNOLOGIES CO., LTD. ALL RIGHTS RESERVED.
//
#endregion

using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Web;
using System.Runtime.CompilerServices;

namespace System
{
    public static class TypeExtensions
    {
        /// <summary>
        /// (强类型)对象克隆。若对象实现ICloneable则返回对象的克隆，否则返回对象本身。
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static TValue Clone<TValue>(this TValue value)
        {
            if (value is ICloneable)
            {
                return (TValue)(value as ICloneable).Clone();
            }
            return value;
        }

        #region Assembly

        /// <summary>
        /// 获取当前程序集中实现了指定接口类型且可实例化的类型
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="interfaceType"></param>
        /// <returns></returns>
        public static List<Type> GetCreatableObjectImplementsInterface(this Assembly assembly, Type interfaceType)
        {
            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException(string.Format(TX.Framework.WindowUI.Properties.Resources.Invail_InterfaceType, interfaceType.Name), "interfaceType");
            }
            List<Type> list = new List<Type>();
            foreach (Type type in assembly.GetTypes())
            {
                if (type.IsImplementsInterface(interfaceType) && !type.IsAbstract && !type.IsInterface)
                {
                    list.Add(type);
                }
            }
            return list;
        }

        #endregion

        #region Enum

        /// <summary>
        /// 
        /// </summary>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static Dictionary<string, string> ToDictionary(this Type enumType)
        {
            Guard.ArgumentOutOfRangeException<Type>("enumType", enumType, t => t.IsEnum == false);

            Dictionary<string, string> list = new Dictionary<string, string>();
            foreach (int value in Enum.GetValues(enumType))
            {
                var key = ((Enum)Enum.Parse(enumType, value.ToString())).GetDescription();
                list[key] = value.ToString();
            }

            return list;
        }

        #endregion

        #region Type

        public static bool IsAnonymous(this Type type)
        {
            return ((type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
              && type.BaseType == typeof(object)
                && Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
                  && type.Name.Contains("AnonymousType")
                    && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic);
        }

        /// <summary>
        /// 判断两种类型是否兼容
        /// </summary>
        /// <param name="type1"></param>
        /// <param name="type2"></param>
        /// <returns></returns>
        public static bool IsCompatibleType(this Type type1, Type type2)
        {
            if (type1 == type2)
                return true;

            if (type1.IsEnum && Enum.GetUnderlyingType(type1) == type2)
                return true;

            Type underlyingType1 = Nullable.GetUnderlyingType(type1);
            Type underlyingType2 = Nullable.GetUnderlyingType(type2);

            if (underlyingType1 != null && underlyingType2 != null)
                return underlyingType1.IsCompatibleType(underlyingType2);

            return false;
        }

        /// <summary>
        /// 判断当前类型是否实现了指定接口
        /// </summary>
        /// <param name="objectType"></param>
        /// <param name="interfaceType"></param>
        /// <returns></returns>
        public static bool IsImplementsInterface(this Type objectType, Type interfaceType)
        {
            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException(string.Format(TX.Framework.WindowUI.Properties.Resources.Invail_InterfaceType, interfaceType.Name), "interfaceType");
            }
            foreach (Type type in objectType.GetInterfaces())
            {
                if (type == interfaceType)
                {
                    return true;
                }
                if (type.Name.Contains("`"))
                {
                    if (type.Name == interfaceType.Name && type.Assembly == interfaceType.Assembly)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        #endregion

        #region object

        ///<summary>
        /// Returns a wrapper <see cref="ValueTypeHolder"/> instance if <paramref name="obj"/> 
        /// is a value type.  Otherwise, returns <paramref name="obj"/>.
        ///</summary>
        ///<param name="obj">An object to be examined.</param>
        ///<returns>A wrapper <seealso cref="ValueTypeHolder"/> instance if <paramref name="obj"/>
        /// is a value type, or <paramref name="obj"/> itself if it's a reference type.</returns>
        public static object WrapIfValueType(this object obj)
        {
            return obj.GetType().IsValueType ? new ValueTypeHolder(obj) : obj;
        }

        ///<summary>
        /// Returns a wrapped object if <paramref name="obj"/> is an instance of <see cref="ValueTypeHolder"/>.
        ///</summary>
        ///<param name="obj">An object to be "erased".</param>
        ///<returns>The object wrapped by <paramref name="obj"/> if the latter is of type <see cref="ValueTypeHolder"/>.  Otherwise,
        /// return <paramref name="obj"/>.</returns>
        public static object UnwrapIfWrapped(this object obj)
        {
            var holder = obj as ValueTypeHolder;
            return holder == null ? obj : holder.Value;
        }

        /// <summary>
        /// Determines whether <paramref name="obj"/> is a wrapped object (instance of <see cref="ValueTypeHolder"/>).
        /// </summary>
        /// <param name="obj">The object to check.</param>
        /// <returns>Returns true if <paramref name="obj"/> is a wrapped object (instance of <see cref="ValueTypeHolder"/>).</returns>
        public static bool IsWrapped(this object obj)
        {
            return obj as ValueTypeHolder != null;
        }

        public static Type GetTypeAdjusted(this object obj)
        {
            var wrapper = obj as ValueTypeHolder;
            return wrapper == null ? obj.GetType() : wrapper.Value.GetType();
        }

        /// <summary>
        /// 判断当前对象是否为指定类型的实例
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsInstanceOfType(this object instance, Type type)
        {
            Type instanceType = instance.GetType();

            foreach (Type iface in instanceType.GetInterfaces())
            {
                if (iface == type)
                {
                    return true;
                }
            }

            Type sType = instanceType;
            while (instanceType != typeof(object))
            {
                if (type == instanceType)
                {
                    return true;
                }
                instanceType = instanceType.BaseType;
            }

            Type dType = type;
            while (dType != null && dType != typeof(object))
            {
                if (dType == sType)
                {
                    return true;
                }
                dType = dType.BaseType;
            }
            return false;
        }

        #endregion

        #region DateTime

        /// <summary>
        /// 是否为有效日期
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsValid(this DateTime value)
        {
            if (DateTime.MinValue == value || DateTime.MaxValue == value)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 转换为中国日期格式
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToCHString(this DateTime value)
        {
            return value.ToString("yyyy-MM-dd");
        }

        public static string ToString(this Nullable<DateTime> dt, string format)
        {
            if (dt == null || dt == DateTime.MinValue || dt == DateTime.MaxValue)
            {
                return string.Empty;
            }
            else
            {
                return ((DateTime)dt).ToString(format);
            }
        }

        #endregion

        #region Int32

        public static bool IsValid(this int value)
        {
            if (int.MinValue == value || int.MaxValue == value)
            {
                return false;
            }
            return true;
        }

        #endregion

        #region String

        public static bool ToBoolean(this string value)
        {
            bool result;
            if (Boolean.TryParse(value, out result))
            {
                return result;
            }
            throw new InvalidCastException("\"" + value + "\"不是有效的时间格式，请确认。");
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsValid(this string value)
        {
            return !string.IsNullOrEmpty(value);
        }

        #endregion

        public static Int32[] ConvertToInt32(this string[] source)
        {
            List<string> list = new List<string>(source);
            return list.ConvertAll(c => c.ToInt32()).ToArray();
        }

        public static Int64[] ConvertToInt64(this string[] source)
        {
            List<string> list = new List<string>(source);
            return list.ConvertAll(c => c.ToInt64()).ToArray();
        }
    }
}
