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

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

namespace Infrastructure.Utilities
{
	public class ExpressionHelper
	{
		public static string GetPropertyName<T, O>(Expression<Func<T, O>> exp)
		{
			MemberExpression memberExpression = null;

			if (exp.Body is MemberExpression)
			{
				memberExpression = exp.Body as MemberExpression;
			}

			if (exp.Body is UnaryExpression)
			{
				var unaryExpression = exp.Body as UnaryExpression;
				if (unaryExpression.Operand is MemberExpression)
				{
					memberExpression = unaryExpression.Operand as MemberExpression;
				}
			}

			if (memberExpression == null)
			{
				throw new InvalidOperationException("Not a member access.");
			}

			var info = memberExpression.Member as PropertyInfo;
			return info.Name;
		}

		public static string GetPropertyName<T>(Expression<Func<T, object>> exp)
		{
			MemberExpression memberExpression = null;

			// Get memberexpression.
			if (exp.Body is MemberExpression)
			{
				memberExpression = exp.Body as MemberExpression;
			}

			if (exp.Body is UnaryExpression)
			{
				var unaryExpression = exp.Body as UnaryExpression;
				if (unaryExpression.Operand is MemberExpression)
				{
					memberExpression = unaryExpression.Operand as MemberExpression;
				}
			}

			if (memberExpression == null)
			{
				throw new InvalidOperationException("Not a member access.");
			}

			var info = memberExpression.Member as PropertyInfo;
			return info.Name;
		}

		public static string GetPropertyName(Expression<Func<object>> exp)
		{
			var memberExpression = exp.Body as MemberExpression;
			if (memberExpression == null)
			{
				throw new InvalidOperationException("Not a member access.");
			}
			var info = memberExpression.Member as PropertyInfo;
			return info.Name;
		}

		public static object GetPropertyNameAndValue(Expression<Func<object>> exp, ref string propName)
		{
			var memberExpression = exp.Body as MemberExpression;
			PropertyInfo propInfo = null;
			if (exp.Body is MemberExpression)
			{
				propInfo = ((MemberExpression)exp.Body).Member as PropertyInfo;
			}
			else if (exp.Body is UnaryExpression)
			{
				Expression op = ((UnaryExpression)exp.Body).Operand;
				propInfo = ((MemberExpression)op).Member as PropertyInfo;
			}

			object val = exp.Compile().DynamicInvoke();
			propName = propInfo.Name;
			return val;
		}

		public static object GetPropertyValue(Expression<Func<object>> exp)
		{
			var memberExpression = exp.Body as MemberExpression;
			PropertyInfo propInfo = null;
			if (exp.Body is MemberExpression)
			{
				propInfo = ((MemberExpression)exp.Body).Member as PropertyInfo;
			}
			else if (exp.Body is UnaryExpression)
			{
				Expression op = ((UnaryExpression)exp.Body).Operand;
				propInfo = ((MemberExpression)op).Member as PropertyInfo;
			}

			object val = exp.Compile().DynamicInvoke();
			return val;
		}

		static void Build<T>(Expression<Func<T, bool>> predicate)
		{
			string format = "{0} {1} {2}";
			BinaryExpression exp = (BinaryExpression)predicate.Body;
			MemberExpression left = (MemberExpression)exp.Left;

			string fieldName = left.Member.Name;
			string operand = RepositoryExpressionTypeHelper.GetText(exp.NodeType);
			string fieldVal = "";
			object rval = null;

			if (exp.Right is ConstantExpression)
			{
				ConstantExpression right = (ConstantExpression)exp.Right;
				fieldVal = RepositoryExpressionValueHelper.GetVal(right.Value);
			}
			else if (exp.Right is MemberExpression)
			{
				MemberExpression right = (MemberExpression)exp.Right;
				rval = Expression.Lambda(exp.Right).Compile().DynamicInvoke();
			}

			// Check for data types.
			PropertyInfo propInfo = left.Member as PropertyInfo;

			// String ? Encode single quotes. ' = ''
			if (propInfo.PropertyType == typeof(string))
			{
				fieldVal = string.Format("'{0}'", fieldVal.Replace("'", "''"));
			}
			else if (propInfo.PropertyType == typeof(DateTime))
			{
				fieldVal = "'" + ((DateTime)rval).ToShortDateString() + "'";
			}

			string val = string.Format(format, fieldName, operand, fieldVal);
			Console.WriteLine(val);
		}
	}

	class RepositoryExpressionValueHelper
	{
		public static string GetVal(object val)
		{
			if (val.GetType() == typeof(bool) || val.GetType() == typeof(Boolean))
			{
				bool boolVal = (bool)val;
				return boolVal == true ? "1" : "0";
			}
			return val.ToString();
		}
	}

	class RepositoryExpressionTypeHelper
	{
		private static IDictionary<ExpressionType, string> _map = new Dictionary<ExpressionType, string>();

		static RepositoryExpressionTypeHelper()
		{
			_map[ExpressionType.Equal] = "=";
			_map[ExpressionType.NotEqual] = "<>";
			_map[ExpressionType.GreaterThanOrEqual] = ">=";
			_map[ExpressionType.LessThanOrEqual] = "<=";
			_map[ExpressionType.LessThan] = "<";
			_map[ExpressionType.GreaterThan] = ">";
		}

		/// <summary>
		/// Get the sql text equivalent of the expression type.
		/// </summary>
		/// <param name="expType"></param>
		/// <returns></returns>
		public static string GetText(ExpressionType expType)
		{
			if (!_map.ContainsKey(expType))
			{
				throw new ArgumentException("expresion type :" + expType.ToString() + "not supported.");
			}
			return _map[expType];
		}
	}
}
