using Apewer;
using Apewer.Internals.QrCode;
using Apewer.Models;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Apewer
{

    /// <summary>类实用工具。</summary>
    public class ClassUtility
    {

        /// <summary>从外部加载对象。</summary>
        public static object CreateObject(string path, string type, bool ignoreCase)
        {
            try
            {
                var a = Assembly.LoadFrom(path);
                var t = a.GetType(type, false, ignoreCase);
                if (t != null)
                {
                    var result = Activator.CreateInstance(t);
                    return result;
                }
            }
            catch { }
            return null;
        }

        /// <summary>解析源对象。</summary>
        public static Dictionary<string, string> GetOrigin(TextSet instance)
        {
            if (instance == null) return null;
            return instance.Origin;
        }

        /// <summary>解析源对象。</summary>
        public static Dictionary<string, object> GetOrigin(ObjectSet instance)
        {
            if (instance == null) return null;
            return instance.Origin;
        }

        /// <summary>解析源对象。</summary>
        public static Dictionary<string, T> GetOrigin<T>(ObjectSet<T> instance) // where T : ObjectSet<T>
        {
            if (instance == null) return null;
            return instance.Origin;
        }

        /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
        public static T GetAttribute<T>(object target) where T : Attribute
        {
            if (target == null) return null;
            try { return GetAttribute<T>(target.GetType()); } catch { return null; }
        }

        /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
        public static T GetAttribute<T>(Type target, bool inherit = false) where T : Attribute
        {
            if (target == null) return null;
            try
            {
                var type = target;
                var attributes = type.GetCustomAttributes(typeof(T), inherit);
                if (attributes.LongLength > 0L)
                {
                    var attribute = attributes[0] as T;
                    return attribute;
                }
            }
            catch { }
            return null;
        }

        /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
        public static T GetAttribute<T>(PropertyInfo property, bool inherit = false) where T : Attribute
        {
            if (property == null) return null;
            try
            {
                var type = property;
                var attributes = type.GetCustomAttributes(typeof(T), inherit);
                if (attributes.LongLength > 0L)
                {
                    var attribute = attributes[0] as T;
                    return attribute;
                }
            }
            catch { }
            return null;
        }

        /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
        public static T GetAttribute<T>(MethodInfo methods, bool inherit = false) where T : Attribute
        {
            if (methods == null) return null;
            try
            {
                var type = methods;
                var attributes = type.GetCustomAttributes(typeof(T), inherit);
                if (attributes.LongLength > 0L)
                {
                    var attribute = attributes[0] as T;
                    return attribute;
                }
            }
            catch { }
            return null;
        }

        /// <summary>获取一个值,指示该属性是否 static。</summary>
        public static bool IsStatic(PropertyInfo property, bool withNonPublic = false)
        {
            if (property == null) return false;

            var getter = property.GetGetMethod();
            if (getter != null) return getter.IsStatic;

            if (withNonPublic)
            {
                getter = property.GetGetMethod(true);
                if (getter != null) return getter.IsStatic;
            }

            var setter = property.GetSetMethod();
            if (setter != null) return setter.IsStatic;

            if (withNonPublic)
            {
                setter = property.GetSetMethod(true);
                if (setter != null) return setter.IsStatic;
            }

            return false;
        }

        /// <summary>调用泛型对象的 ToString() 方法。</summary>
        public static string ToString<T>(T target)
        {
            var type = typeof(T);
            var methods = type.GetMethods();
            foreach (var method in methods)
            {
                if (method.Name != "ToString") continue;
                if (method.GetParameters().LongLength > 0L) continue;
                var result = (string)method.Invoke(target, null);
                return result;
            }
            return null;
        }

        /// <summary>调用方法。</summary>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="MethodAccessException"></exception>
        /// <exception cref="NotSupportedException"></exception>
        /// <exception cref="TargetException"></exception>
        /// <exception cref="TargetInvocationException"></exception>
        /// <exception cref="TargetParameterCountException"></exception>
        public static object InvokeMethod(object instance, MethodInfo method, params object[] parameters)
        {
            if (instance == null || method == null) return null;
            {
                var pis = method.GetParameters();
                if (pis == null || pis.Length < 1)
                {
                    return method.Invoke(instance, null);
                }
            }
            {
                if (parameters == null) return method.Invoke(instance, new object[] { null });
                return method.Invoke(instance, parameters);
            }
        }

        /// <summary>获取属性值。</summary>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="MethodAccessException"></exception>
        /// <exception cref="NotSupportedException"></exception>
        /// <exception cref="TargetException"></exception>
        /// <exception cref="TargetInvocationException"></exception>
        /// <exception cref="TargetParameterCountException"></exception>
        public static T InvokeGet<T>(object instance, PropertyInfo property)
        {
            if (instance == null || property == null || !property.CanRead) return default;
#if NET20 || NET40
            var getter = property.GetGetMethod();
            if (getter != null)
            {
                try
                {
                    var value = getter.Invoke(instance, null);
                    if (value != null)
                    {
                        return (T)value;
                    }
                }
                catch { }
            }
            return default;
#else
            var value = property.GetValue(instance);
            try { return (T)value; } catch { return default; }
#endif
        }

        /// <summary>设置属性值。</summary>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="MethodAccessException"></exception>
        /// <exception cref="NotSupportedException"></exception>
        /// <exception cref="TargetException"></exception>
        /// <exception cref="TargetInvocationException"></exception>
        /// <exception cref="TargetParameterCountException"></exception>
        public static void InvokeSet<T>(object instance, PropertyInfo property, T value)
        {
            if (instance == null || property == null || !property.CanWrite) return;
#if NET20 || NET40
            var setter = property.GetSetMethod();
            if (setter != null)
            {
                try {
                    setter.Invoke(instance, new object[] { value });
                }
                catch { }
            }
#else
            property.SetValue(instance, value);
#endif
        }

        /// <summary>指示方法是否存在于指定类型中。</summary>
        public static bool ExistIn(MethodInfo method, Type type)
        {
            if (method == null) return false;
            if (type == null) return false;
            return type.Equals(method.DeclaringType.Equals(type));
        }

        /// <summary>指示方法是否存在于指定类型中。</summary>
        public static bool ExistIn<T>(MethodInfo method)
        {
            if (method == null) return false;
            var type = typeof(T);
            return type.Equals(method.DeclaringType.Equals(type));
        }

        /// <summary>判断指定类型可序列化。</summary>
        public static bool CanSerialize(Type type, bool inherit = false)
        {
            if (type == null) return false;

            var nsas = type.GetCustomAttributes(typeof(NonSerializedAttribute), inherit);
            if (nsas != null && nsas.Length > 0) return false;

            var sas = type.GetCustomAttributes(typeof(SerializableAttribute), inherit);
            if (sas == null || sas.Length < 1) return false;

            return true;
        }

        /// <summary>判断指定类型具有特性。</summary>
        private static bool ContainsAttribute<T>(object[] attributes) where T : Attribute
        {
            if (attributes == null) return false;
            if (attributes.Length < 1) return false;
            return true;
        }

        /// <summary>判断指定类型具有特性。</summary>
        public static bool ContainsAttribute<T>(Type type, bool inherit = false) where T : Attribute
        {
            return type == null ? false : ContainsAttribute<T>(type.GetCustomAttributes(typeof(T), inherit));
        }

        /// <summary>判断指定属性具有特性。</summary>
        public static bool ContainsAttribute<T>(PropertyInfo property, bool inherit = false) where T : Attribute
        {
            return property == null ? false : ContainsAttribute<T>(property.GetCustomAttributes(typeof(T), inherit));
        }

        /// <summary>判断基类。</summary>
        public static bool IsInherits(Type child, Type @base)
        {
            // 检查参数。
            if (child == null || @base == null) return false;

            // 忽略 System.Object。
            var quantum = typeof(object);
            if (@base.Equals(quantum)) return true;
            if (child.Equals(quantum)) return true;

            // 循环判断基类。
            var current = child;
            while (true)
            {
                var parent = current.BaseType;
                if (parent.Equals(@base)) return true;
                if (parent.Equals(quantum)) break;
                current = parent;
            }

            return false;
        }

        /// <summary></summary>
        public static IEnumerable<Type> GetTypes(Assembly assembly)
        {
            if (assembly == null) return null;

            var types = null as IEnumerable<Type>;

            if (types == null)
            {
                try { types = assembly.GetExportedTypes(); }
                catch { types = null; }
            }

            if (types == null)
            {
                try { types = assembly.GetTypes(); }
                catch { types = null; }
            }

            return types;
        }

        /// <summary>能从外部创建对象实例。</summary>
        public static bool CanNewClass<T>()
        {
            return CanNewClass(typeof(T));
        }

        /// <summary>能从外部创建对象实例。</summary>
        public static bool CanNewClass(Type type)
        {
            if (type == null) return false;
            if (!type.IsClass) return false;
            if (type.IsAbstract) return false;

            var methods = type.GetMethods();
            var constructors = type.GetConstructors();
            foreach (var i in constructors)
            {
                if (i.IsPublic)
                {
                    var parameters = i.GetParameters();
                    if (parameters.Length < 1)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>克隆对象,创建新对象。可指定包含对象的属性和字段。</summary>
        public static T Clone<T>(T current, T failed = default(T), bool properties = true, bool fields = false) where T : new()
        {
            if (current == null) return default(T);

            var type = typeof(T);
            var target = new T();
            foreach (var property in type.GetProperties())
            {
                var getter = property.GetGetMethod();
                var setter = property.GetSetMethod();
                if (getter == null || setter == null) continue;

                var value = getter.Invoke(current, null);
                setter.Invoke(target, new object[] { value });
            }
            foreach (var field in type.GetFields())
            {
                var value = field.GetValue(current);
                field.SetValue(target, value);
            }

            return target;
        }

        /// <summary>对每个属性执行动作。</summary>
        public static void ForEachProperties(object instance, Action<Property> action, bool withNonPublic = true, bool withStatic = false)
        {
            if (instance == null || action == null) return;
            var type = instance.GetType();
            if (type == null) return;

            var properties = new List<PropertyInfo>();
            properties.AddRange(type.GetProperties());
            if (withNonPublic) properties.AddRange(type.GetProperties(BindingFlags.NonPublic));
            foreach (var info in properties)
            {
                var arg = new Property()
                {
                    Instance = instance,
                    Type = type,
                    Information = info,
                    Getter = info.GetGetMethod(),
                    Setter = info.GetSetMethod()
                };
                if (arg.IsStatic && !withStatic) continue;
                action.Invoke(arg);
            }
        }

        /// <summary>遍历属性。</summary>
        public static void ForEachPublicProperties(object instance, Action<PropertyInfo> action)
        {
            if (instance != null && action != null) ForEachPublicProperties(instance.GetType(), action);
        }

        /// <summary>遍历属性。</summary>
        public static void ForEachPublicProperties(Type type, Action<PropertyInfo> action)
        {
            if (type == null || action == null) return;
            foreach (var property in type.GetProperties()) action.Invoke(property);
        }

        /// <summary>检查类型。</summary>
        public static bool TypeEquals(object instance, Type type)
        {
            if (instance == null) return type == null ? true : false;
            if (instance is PropertyInfo)
            {
                return ((PropertyInfo)instance).PropertyType.Equals(type);
            }
            if (instance is MethodInfo)
            {
                return ((MethodInfo)instance).ReturnType.Equals(type);
            }
            return instance.GetType().Equals(type);
        }

        /// <summary>检查类型。</summary>
        public static bool TypeEquals<T>(object instance)
        {
            return TypeEquals(instance, typeof(T));
        }

        /// <summary>安全转换为 List&lt;<typeparamref name="T"/>&gt; 对象。可指定排除 NULL 值元素。</summary>
        /// <typeparam name="T"></typeparam>
        public static List<T> ToList<T>(IEnumerable<T> objects, bool excludeNull = false)
        {
            var list = new List<T>();
            if (objects != null)
            {
                foreach (var value in objects)
                {
                    if (excludeNull && value == null) continue;
                    list.Add(value);
                }
            }
            return list;
        }

        /// <summary></summary>
        public static bool IsEmpty<T>(IEnumerable<T> objects)
        {
            if (objects == null) return true;
            foreach (var i in objects) return false;
            return true;
        }

        /// <summary></summary>
        public static bool NotEmpty<T>(IEnumerable<T> objects)
        {
            if (objects == null) return false;
            foreach (var i in objects) return true;
            return false;
        }

        /// <summary></summary>
        public static bool Contains<T>(IEnumerable<T> objects, T cell)
        {
            if (objects == null) return false;
            var a = (object)cell;
            foreach (var i in objects)
            {
                var b = (object)i;
                if (a == b) return true;
            }
            return false;
        }

        /// <summary></summary>
        public static List<T> Sub<T>(IEnumerable<T> objects, long start = 0, long count = -1, Func<T> stuffer = null)
        {
            if (count == 0) return new List<T>();

            var hasCount = count > 0L;
            var output = new List<T>();

            if (start < 0)
            {
                for (var i = start; i < 0; i++)
                {
                    output.Add(stuffer == null ? default : stuffer());
                    if (hasCount && output.Count >= count) return output;
                }
            }

            if (objects != null)
            {
                var offset = 0L;
                foreach (var i in objects)
                {
                    if (offset < start)
                    {
                        offset += 1L;
                        continue;
                    }
                    offset += 1L;

                    output.Add(i);
                    if (hasCount && output.Count >= count) return output;
                }
            }

            while (hasCount && output.Count < count)
            {
                output.Add(stuffer == null ? default : stuffer());
            }

            return output;
        }

    }

}