using System;
using System.CodeDom;

namespace XTensions.OOCodeDOM
{
	public class Expression
	{
		protected CodeExpression e;

		public Expression (CodeExpression e)
		{
			this.e = e;
		}

		public static implicit operator CodeExpression (Expression e)
		{
			return e.e;
		}

		public static implicit operator CodeStatement (Expression e)
		{
			return Make.Statement(e);
		}

		public override bool Equals (object o)
		{
			throw new Exception();
		}

		public override int GetHashCode ()
		{
			throw new Exception();
		}

		// Binary operators

		public static Expression operator + (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.Add, e2));
		}

		public static Expression operator - (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.Subtract, e2));
		}

		public static Expression operator * (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.Multiply, e2));
		}

		public static Expression operator / (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.Divide, e2));
		}

		public static Expression operator % (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.Modulus, e2));
		}

		public static Expression operator & (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.BitwiseAnd, e2));
		}

		public static Expression operator | (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.BitwiseOr, e2));
		}

		public static Expression operator ^ (Expression e1, Expression e2)
		{
			return (e1 | e2) & ~(e1 & e2);
		}

		public static Expression operator == (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.IdentityEquality, e2));
		}

		public static Expression operator != (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.IdentityInequality, e2));
		}

		public static Expression operator < (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.LessThan, e2));
		}

		public static Expression operator <= (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.LessThanOrEqual, e2));
		}

		public static Expression operator > (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.GreaterThan, e2));
		}

		public static Expression operator >= (Expression e1, Expression e2)
		{
			return new Expression(new CodeBinaryOperatorExpression(e1, CodeBinaryOperatorType.GreaterThanOrEqual, e2));
		}

		// Unary operators

		public static Expression operator + (Expression e1)
		{
			return new Expression(e1);
		}

		public static Expression operator - (Expression e1)
		{
			return Make.Constant(0) - e1;
		}

		public static Expression operator ~ (Expression e1)
		{
			return Make.Constant(-1) - e1;
		}

		public static Expression operator ! (Expression e1)
		{
			return e1 == Make.Constant(false);
		}

		// Other operators

		public Expression this [params CodeExpression[] e]
		{
			get
			{
				return new Expression(new CodeArrayIndexerExpression(this, e));
			}
		}
	}
}
