//==============================================================
//  版权所有：深圳杰文科技
//  文件名：ReflectHelper.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Forms;

namespace Infrastructure.Utilities
{
	//[DebuggerStepThrough]
	public static class ReflectHelper
	{
		public static MethodInfo GetMethod<TClass>(Expression<Action<TClass>> expression)
		{
			var methodCall = expression.Body as MethodCallExpression;
			if (methodCall == null)
			{
				throw new ArgumentException("Expected method call");
			}
			return methodCall.Method;
		}

		public static PropertyInfo GetProperty<TClass>(Expression<Func<TClass, object>> expression)
		{
			MemberExpression memberExpression;
			var unary = expression.Body as UnaryExpression;
			if (unary != null)
			{
				memberExpression = unary.Operand as MemberExpression;
			}
			else
			{
				memberExpression = expression.Body as MemberExpression;
			}
			if (memberExpression == null || !(memberExpression.Member is PropertyInfo))
			{
				throw new ArgumentException("Expected property expression");
			}
			return (PropertyInfo)memberExpression.Member;
		}

		public static PropertyInfo GetProperty(Type type, string propertyName)
		{
			PropertyInfo pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
			return pi;
		}

		public static void SetProperty(object obj, string propertyName, object value)
		{
			PropertyInfo pi = GetProperty(obj.GetType(), propertyName);
			pi.SetValue(obj, value, null);
		}

		public static List<FieldInfo> GetFieldList(Type type)
		{
			FieldInfo[] fieldInfoes = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
			return fieldInfoes.ToList();
		}

		public static FieldInfo GetField(Type type, string fieldName)
		{
			FieldInfo fieldInfo = type.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
			return fieldInfo;
		}

		public static void SetField(object obj, string fieldName, object value)
		{
			FieldInfo fieldInfo = GetField(obj.GetType(), fieldName);
			fieldInfo.SetValue(obj, value);
		}

		public static List<PropertyInfo> GetPropertyList(Type type)
		{
			PropertyInfo[] propertyInfoes = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
			return propertyInfoes.ToList();
		}

		public static List<PropertyInfo> GetPropertyList(Type classType, Type attributeType)
		{
			List<PropertyInfo> list = new List<PropertyInfo>();
			foreach (PropertyInfo pi in GetPropertyList(classType))
			{
				if (pi.GetCustomAttributes(attributeType, false).Length > 0)
				{
					list.Add(pi);
				}
			}
			return list;
		}

		public static Value GetPropertyValue<Value>(object obj, string propertyName)
		{
			PropertyInfo pi = obj.GetType().GetProperty(propertyName);
			if (pi == null)
			{
				return default(Value);
			}

			object value = pi.GetValue(obj, null);
			return (Value)value;
		}

		public static object GetPropertyValue(object obj, string propertyName)
		{
			PropertyInfo pi = obj.GetType().GetProperty(propertyName);
			if (pi == null)
			{
				return null;
			}

			object value = pi.GetValue(obj, null);
			return value;
		}

		public static Dictionary<Type, T> GetClassList<T>(string nameStrategy) where T : Attribute
		{
			Dictionary<Type, T> classList = new Dictionary<Type, T>();

			Type attributeType = typeof(T);
			foreach (Assembly asm in AssemblyHelper.LoadAll(Application.StartupPath, nameStrategy))
			{
				foreach (Type type in asm.GetTypes())
				{
					object[] attributes = type.GetCustomAttributes(attributeType, false);
					if (attributes.Length > 0)
					{
						classList.Add(type, (T)attributes[0]);
					}
				}
			}

			return classList;
		}

		public static Type GetFirstClass<T>(string nameStrategy) where T : Attribute
		{
			Type attributeType = typeof(T);
			foreach (Assembly asm in AssemblyHelper.LoadAll(Application.StartupPath, nameStrategy))
			{
				foreach (Type type in asm.GetTypes())
				{
					if (type.GetCustomAttributes(attributeType, false).Length > 0)
					{
						return type;
					}
				}
			}
			return null;
		}

		public static void InvokeMethod(object obj, string methodName)
		{
			MethodInfo mi = obj.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
			if (mi != null)
			{
				mi.Invoke(obj, null);
			}
		}

		public static List<Type> GetClassList<T>()
		{
			List<Type> list = new List<Type>();
			foreach (Assembly asm in AssemblyHelper.LoadAll(Application.StartupPath, ""))
			{
				foreach (Type type in asm.GetTypes())
				{
					if (type is T)
					{
						list.Add(type);
					}
				}
			}
			return list;
		}

		//fieldValue：字段值；pi：Entity的属性信息。
		public static object ConvertValue(object fieldValue, PropertyInfo pi)
		{
			Type fieldValueType = fieldValue.GetType();

			if (fieldValueType == typeof(decimal))
			{
				if (pi.PropertyType == typeof(bool) || pi.PropertyType == typeof(Nullable<bool>))
				{
					if (fieldValue != null)
					{
						fieldValue = (decimal)fieldValue == 0 ? false : true;
					}
				}
				else if (pi.PropertyType == typeof(int) || pi.PropertyType == typeof(Nullable<int>))
				{
					fieldValue = (int)((decimal)fieldValue);
				}
				else if (pi.PropertyType == typeof(short) || pi.PropertyType == typeof(Nullable<short>))
				{
					fieldValue = (short)((decimal)fieldValue);
				}
				else if (pi.PropertyType == typeof(Int64) || pi.PropertyType == typeof(Nullable<Int64>))
				{
					fieldValue = (Int64)((decimal)fieldValue);
				}
				else if (pi.PropertyType == typeof(double) || pi.PropertyType == typeof(Nullable<double>))
				{
					fieldValue = (double)((decimal)fieldValue);
				}
				else
				{
					fieldValue = Math.Round((decimal)fieldValue, DataTableHelper.DecimalDigit);
				}
			}
			else if (fieldValueType == typeof(int))
			{
				if (pi.PropertyType == typeof(long) || pi.PropertyType == typeof(Nullable<long>))
				{
					fieldValue = (long)(int)fieldValue;
				}
				else if (pi.PropertyType == typeof(string))
				{
					fieldValue = fieldValue.ToString();
				}
				else if (pi.PropertyType == typeof(bool))
				{
					fieldValue = (int)fieldValue == 1;
				}
			}
			else if (fieldValueType == typeof(long))
			{
				if (pi.PropertyType == typeof(int) || pi.PropertyType == typeof(Nullable<int>))
				{
					fieldValue = (int)((long)fieldValue);
				}
				else if (pi.PropertyType == typeof(bool))
				{
					fieldValue = (long)fieldValue != 0;
				}
			}
			else if (fieldValueType == typeof(uint))
			{
				if (pi.PropertyType == typeof(Nullable<long>))
				{
					fieldValue = (long)(uint)fieldValue;
				}
			}
			else if (fieldValueType == typeof(Int16))
			{
				if (pi.PropertyType == typeof(bool) || pi.PropertyType == typeof(Nullable<bool>))
				{
					if (fieldValue != null)
					{
						fieldValue = (bool)((Int16)fieldValue == 0 ? false : true);
					}
				}
				else if (pi.PropertyType == typeof(Nullable<int>))
				{
					fieldValue = (int)(Int16)fieldValue;
				}
			}
			else if (fieldValueType == typeof(double))
			{
				if (pi.PropertyType == typeof(decimal) || pi.PropertyType == typeof(Nullable<decimal>))
				{
					fieldValue = (decimal)((double)fieldValue);
				}
			}
			else if (fieldValueType == typeof(DateTime))
			{
				if (pi.PropertyType == typeof(string))
				{
					fieldValue = ((DateTime)fieldValue).ToString("yyyy-MM-dd HH:mm:ss");
				}
			}
			else if (fieldValueType == typeof(Guid))
			{
				if (pi.PropertyType == typeof(string))
				{
					fieldValue = fieldValue.ToString();
				}
			}
			else if (fieldValueType == typeof(byte))
			{
				if (pi.PropertyType == typeof(short))
				{
					fieldValue = (short)(byte)fieldValue;
				}
				else if (pi.PropertyType == typeof(bool) || pi.PropertyType == typeof(Nullable<bool>))
				{
					fieldValue = (bool)((byte)fieldValue == 1 ? true : false);
				}
			}
			else if (fieldValueType == typeof(sbyte))
			{
				if (pi.PropertyType == typeof(bool) || pi.PropertyType == typeof(Nullable<bool>))
				{
					fieldValue = (bool)((sbyte)fieldValue == 1 ? true : false);
				}
			}
			return fieldValue;
		}

		public static List<MethodInfo> GetMethodList(Type type)
		{
			BindingFlags bindings = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo[] methodInfoList = type.GetMethods(bindings);
			return methodInfoList.ToList();
		}

	}
}