csharp/Adoxio/xRM-Portals-Community-Edition/Framework/Adxstudio.Xrm/Web/UI/WebForms/Expression.cs

Expression.cs
/*
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the MIT License. See License.txt in the project root for license information.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Adxstudio.Xrm.Core;
using Adxstudio.Xrm.Resources;
using Adxstudio.Xrm.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Metadata;

namespace Adxstudio.Xrm.Web.UI.WebForms
{
	public abstract clast Expression : IEnumerable
	{
		public IEnumerable Operands { get; private set; }

		public virtual string Operator
		{
			get { return null; }
		}

		public delegate string ExpressionAction(Expression expression, IDictionary map);

		protected Expression()
		{
		}

		protected Expression(string name, object value)
			: this(new LeftLiteralExpression(name.Trim()), new RightLiteralExpression(value))
		{
		}

		protected Expression(params Expression[] operands)
		{
			Operands = new List(operands);
		}

		public static LiteralExpression Literal(object value)
		{
			return new LiteralExpression(value);
		}

		public static OrExpression operator |(Expression left, Expression right)
		{
			return new OrExpression(left, right);
		}

		public static OrExpression Or(params Expression[] operands)
		{
			return new OrExpression(operands);
		}

		public static AndExpression operator &(Expression left, Expression right)
		{
			return new AndExpression(left, right);
		}

		public static AndExpression And(params Expression[] operands)
		{
			return new AndExpression(operands);
		}

		public static NotExpression Not(Expression operand)
		{
			return new NotExpression(operand);
		}

		public static NoOpExpression NoOp(Expression operand)
		{
			return new NoOpExpression(operand);
		}

		public static LikeExpression Like(string name, object value)
		{
			return new LikeExpression(name, value);
		}

		public static NotLikeExpression NotLike(string name, object value)
		{
			return new NotLikeExpression(name, value);
		}

		public static Expression operator ==(Expression left, Expression right)
		{
			return new EqualsExpression(left, right);
		}

		public static EqualsExpression Equals(string name, object value)
		{
			return new EqualsExpression(name, value);
		}

		public static Expression operator !=(Expression left, Expression right)
		{
			return new NotEqualsExpression(left, right);
		}

		public static NotEqualsExpression NotEquals(string name, object value)
		{
			return new NotEqualsExpression(name, value);
		}

		public static Expression operator >(Expression left, Expression right)
		{
			return new GreaterThanExpression(left, right);
		}

		public static GreaterThanExpression GreaterThan(string name, object value)
		{
			return new GreaterThanExpression(name, value);
		}

		public static Expression operator >=(Expression left, Expression right)
		{
			return new GreaterThanOrEqualsExpression(left, right);
		}

		public static GreaterThanOrEqualsExpression GreaterThanOrEquals(string name, object value)
		{
			return new GreaterThanOrEqualsExpression(name, value);
		}

		public static Expression operator  0) && (current.ToString() == "&" | current.ToString() == "|"))
					{
						if (op != null)
						{
							var operand = GetExpression(op, name.ToString(), operands, parseValue);
							operands.Add(operand);
							unionOperandCount++;
							name.Clear();
						}

						op = current.ToString();

						if (union && unionAnd && current.ToString() == "|")
						{
							var unionOperand = GetExpression("&", "&", operands, parseValue);
							operands.Clear();
							operands.Add(unionOperand);
							unionOperandCount = 1;
						}
						if (union && !unionAnd && current.ToString() == "&")
						{
							var unionOperand = GetExpression("|", "|", operands, parseValue);
							operands.Clear();
							operands.Add(unionOperand);
							unionOperandCount = 1;
						}
						union = true;
						unionAnd = current.ToString() == "&";
					}
					else
					{
						// encountered an operator
						op = current.ToString();
						name.Append(current);

						// check if this is a 2 character operator
						if (reader.Peek() > -1)
						{
							var next = Convert.ToChar(reader.Peek());

							if ("=".Contains(next.ToString()))
							{
								// read the second character
								reader.Read();
								op += next;
								name.Append(next);
							}
						}
					}
				}
				else
				{
					// this is a character in a literal value
					name.Append(current);
				}
			}

			if (union)
			{
				if (operands.Count 
					{
						if (expression is LiteralExpression && (expression as LiteralExpression).Value is string)
						{
							// replace '@' parameter identifiers into the actual parameter value

							var value = (expression as LiteralExpression).Value as string;

							if (value != null && value.StartsWith("@"))
							{
								if (parameters != null && parameters.ContainsKey(value))
								{
									(expression as LiteralExpression).Value = parameters[value];
								}
								else
								{
									value = value.TrimStart('@'); // the '@' character is optional in the parameter dictionary

									if (parameters != null && parameters.ContainsKey(value))
									{
										(expression as LiteralExpression).Value = parameters[value];
									}
									else
									{
										throw new InvalidOperationException(string.Format("The filter parameter {0} is missing an actual value in the dictionary.", value));
									}
								}
							}
						}

						return expression;
					});
		}

		public Expression Clone()
		{
			return Clone((expression, parent) => expression);
		}

		public Expression Clone(Func convert)
		{
			return Clone(convert, null);
		}

		public abstract Expression Clone(Func convert, Expression parent);

		public IEnumerator GetEnumerator()
		{
			if (Operands != null)
			{
				foreach (var operand in Operands)
				{
					yield return operand;
				}
			}
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			yield return GetEnumerator();
		}

		public bool Equals(Expression other)
		{
			if (ReferenceEquals(null, other))
			{
				return false;
			}
			return ReferenceEquals(this, other) || Equals(other.Operands, Operands);
		}

		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj))
			{
				return false;
			}
			if (ReferenceEquals(this, obj))
			{
				return true;
			}
			return obj.GetType() == typeof(Expression) && Equals((Expression)obj);
		}

		public override int GetHashCode()
		{
			return (Operands != null ? Operands.GetHashCode() : 0);
		}
	}

	public clast LiteralExpression : Expression
	{
		public object Value { get; set; }

		public LiteralExpression(object value)
		{
			if (value is string && !string.IsNullOrWhiteSpace((string)value))
			{
				value = ((string)value).Trim(new[] { ' ', '\'' });

				if (((string)value).ToLowerInvariant() == "null")
				{
					value = null;
				}
			}
			
			Value = value;
		}

		public override string ToString(IDictionary map)
		{
			var value = base.ToString(map) ?? (Value == null ? "NULL" : Value.ToString());

			return value;
		}

		public override Expression Clone(Func convert, Expression parent)
		{
			return convert(new LiteralExpression(Value), parent);
		}

		public override bool Evaluate(IExpressionEvaluator evaluator)
		{
			// this method should be guarded from being called by all BinaryExpressions

			throw new NotSupportedException(string.Format("Unable to evaluate an expression of type {0} with the value {1}.", this, Value));
		}
	}

	public clast LeftLiteralExpression : LiteralExpression
	{
		public LeftLiteralExpression(object value) : base(value)
		{
		}

		public override Expression Clone(Func convert, Expression parent)
		{
			return convert(new LeftLiteralExpression(Value), parent);
		}
	}

	public clast RightLiteralExpression : LiteralExpression
	{
		public RightLiteralExpression(object value)
			: base(value)
		{
		}

		public override Expression Clone(Func convert, Expression parent)
		{
			return convert(new RightLiteralExpression(Value), parent);
		}
	}

	public abstract clast BooleanExpression : Expression
	{
		protected BooleanExpression(params Expression[] operands)
			: base(operands)
		{
		}

		public override string ToString(IDictionary map)
		{
			var value = base.ToString(map);

			if (value == null)
			{
				var ops = Operands.Select(operand => operand.ToString(map)).ToList();

				var opsArray = new string[ops.Count];
				ops.CopyTo(opsArray);

				//value = "(\n" + string.Join(" " + Operator + " ", opsArray) + "\n)\n";
				value = string.Format("({0})", string.Join(" " + Operator + " ", opsArray));
			}

			return value;
		}

		public override Expression Clone(Func convert, Expression parent)
		{
			return convert(Clone(Operands.Select(operand => operand.Clone(convert, this)).ToArray()), parent);
		}

		public override bool Evaluate(IExpressionEvaluator evaluator)
		{
			return Evaluate(Operands.Select(operand => operand.Evaluate(evaluator)));
		}

		public abstract Expression Clone(Expression[] operands);

		protected abstract bool Evaluate(IEnumerable operands);
	}

	public clast OrExpression : BooleanExpression
	{
		public OrExpression(params Expression[] operands)
			: base(operands)
		{
		}

		public override string Operator
		{
			get { return "or"; }
		}

		public override Expression Clone(Expression[] operands)
		{
			return new OrExpression(operands);
		}

		protected override bool Evaluate(IEnumerable operands)
		{
			// find any expression that is true

			return operands.Any(operand => operand);
		}
	}

	public clast AndExpression : BooleanExpression
	{
		public AndExpression(params Expression[] operands)
			: base(operands)
		{
		}

		public override string Operator
		{
			get { return "and"; }
		}

		public override Expression Clone(Expression[] operands)
		{
			return new AndExpression(operands);
		}

		protected override bool Evaluate(IEnumerable operands)
		{
			// find any expression that is false

			return !operands.Any(operand => !operand);
		}
	}

	public abstract clast UnaryExpression : Expression
	{
		protected UnaryExpression(Expression operand)
			: base(operand)
		{
		}

		public Expression GetOperand()
		{
			var enumerator = Operands.GetEnumerator();
			enumerator.MoveNext();
			return enumerator.Current;
		}

		public override string ToString(IDictionary map)
		{
			var value = base.ToString(map);

			if (value == null)
			{
				var operand = GetOperand();

				// default to postfix notation
				value = string.Format(@"{0} ({1})", Operator, operand.ToString(map));
			}

			return value;
		}

		public override Expression Clone(Func convert, Expression parent)
		{
			var operand = GetOperand();
			return convert(Clone(operand.Clone(convert, this)), parent);
		}

		public override bool Evaluate(IExpressionEvaluator evaluator)
		{
			// past the operand through

			return Evaluate(GetOperand().Evaluate(evaluator));
		}

		public abstract Expression Clone(Expression operand);

		protected abstract bool Evaluate(bool operand);
	}

	public clast NotExpression : UnaryExpression
	{
		public NotExpression(Expression operand)
			: base(operand)
		{
		}

		public override string Operator
		{
			get { return "not"; }
		}

		public override Expression Clone(Expression operand)
		{
			return new NotExpression(operand);
		}

		protected override bool Evaluate(bool operand)
		{
			// negate the operand

			return !operand;
		}
	}

	public clast NoOpExpression : UnaryExpression
	{
		public NoOpExpression(Expression operand)
			: base(operand)
		{
		}

		public override string ToString(IDictionary map)
		{
			var value = base.ToString(map);

			if (value == null)
			{
				var operand = GetOperand();
				value = string.Format(@"({0})", operand.ToString(map));
			}

			return value;
		}

		public override Expression Clone(Expression operand)
		{
			return new NoOpExpression(operand);
		}

		protected override bool Evaluate(bool operand)
		{
			// past the operand through

			return operand;
		}
	}

	public abstract clast BinaryExpression : Expression
	{
		protected BinaryExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		protected BinaryExpression(string name, object value)
			: base(name, value)
		{
		}

		public Expression Left
		{
			get
			{
				var enumerator = Operands.GetEnumerator();
				enumerator.MoveNext();
				return enumerator.Current;
			}
		}

		public Expression Right
		{
			get
			{
				var enumerator = Operands.GetEnumerator();
				enumerator.MoveNext();
				enumerator.MoveNext();
				return enumerator.Current;
			}
		}

		public override string ToString(IDictionary map)
		{
			var value = base.ToString(map);

			if (value == null)
			{
				var ops = new List(2);
				ops.AddRange(Operands.Cast());

				// default to infix notation
				value = string.Format(@"({1} {0} {2})", Operator, ops[0].ToString(map), ops[1].ToString(map));
			}

			return value;
		}

		public override Expression Clone(Func convert, Expression parent)
		{
			var left = Left.Clone(convert, this);
			var right = Right.Clone(convert, this);

			return convert(Clone(left, right), parent);
		}

		public override bool Evaluate(IExpressionEvaluator evaluator)
		{
			return evaluator.Evaluate(this);
		}

		public abstract Expression Clone(Expression left, Expression right);
	}

	public clast LikeExpression : BinaryExpression
	{
		public LikeExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public LikeExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return "like"; }
		}

		public override Expression Clone(Expression left, Expression right)
		{
			return new LikeExpression(left, right);
		}
	}

	
	public clast NotLikeExpression : BinaryExpression
	{
		public NotLikeExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public NotLikeExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return "not like"; }
		}

		public override Expression Clone(Expression left, Expression right)
		{
			return new NotLikeExpression(left, right);
		}
	}

	
	public clast EqualsExpression : BinaryExpression
	{
		public EqualsExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public EqualsExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return "="; }
		}

		public override Expression Clone(Expression left, Expression right)
		{
			return new EqualsExpression(left, right);
		}
	}

	
	public clast NotEqualsExpression : BinaryExpression
	{
		public NotEqualsExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public NotEqualsExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return ""; }
		}

		public override Expression Clone(Expression left, Expression right)
		{
			return new NotEqualsExpression(left, right);
		}
	}

	
	public clast GreaterThanExpression : BinaryExpression
	{
		public GreaterThanExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public GreaterThanExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return ">"; }
		}

		public override Expression Clone(Expression left, Expression right)
		{
			return new GreaterThanExpression(left, right);
		}
	}

	
	public clast GreaterThanOrEqualsExpression : BinaryExpression
	{
		public GreaterThanOrEqualsExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public GreaterThanOrEqualsExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return ">="; }
		}

		public override Expression Clone(Expression left, Expression right)
		{
			return new GreaterThanOrEqualsExpression(left, right);
		}
	}

	
	public clast LessThanExpression : BinaryExpression
	{
		public LessThanExpression(Expression left, Expression right)
			: base(left, right)
		{
		}

		public LessThanExpression(string name, object value)
			: base(name, value)
		{
		}

		public override string Operator
		{
			get { return "