package lama.mysql.ast;

import lama.IgnoreMeException;
import lama.Randomly;
import lama.mysql.ast.MySQLCastOperation.CastType;

public class MySQLBinaryOperation extends MySQLExpression {

	private final MySQLExpression left;
	private final MySQLExpression right;
	private final MySQLBinaryOperator op;

	public enum MySQLBinaryOperator {

		AND("&") {
			@Override
			public MySQLConstant apply(MySQLConstant left, MySQLConstant right) {
				if (left.isNull() || right.isNull()) {
					return MySQLConstant.createNullConstant();
				} else {
					long leftVal = left.castAs(CastType.SIGNED).getInt();
					long rightVal = right.castAs(CastType.SIGNED).getInt();
					long value = leftVal & rightVal;
					return MySQLConstant.createUnsignedIntConstant(value);
				}
			}
		};

		private String textRepresentation;

		private MySQLBinaryOperator(String textRepresentation) {
			this.textRepresentation = textRepresentation;
		}

		public String getTextRepresentation() {
			return textRepresentation;
		}

		public abstract MySQLConstant apply(MySQLConstant left, MySQLConstant right);

		public static MySQLBinaryOperator getRandom() {
			return Randomly.fromOptions(values());
		}

	}

	public MySQLBinaryOperation(MySQLExpression left, MySQLExpression right, MySQLBinaryOperator op) {
		this.left = left;
		this.right = right;
		this.op = op;
	}

	@Override
	public MySQLConstant getExpectedValue() {
		MySQLConstant leftExpected = left.getExpectedValue();
		MySQLConstant rightExpected = right.getExpectedValue();

		/* workaround for https://bugs.mysql.com/bug.php?id=95960 */
		if (leftExpected.isString()) {
			String text = leftExpected.castAsString();
			while ((text.startsWith(" ") || text.startsWith("\t")) && text.length() > 0) {
				text = text.substring(1);
			}
			if (text.length() > 0 && (text.startsWith("\n") || text.startsWith("."))) {
				throw new IgnoreMeException();
			}
		}

		if (rightExpected.isString()) {
			String text = rightExpected.castAsString();
			while ((text.startsWith(" ") || text.startsWith("\t")) && text.length() > 0) {
				text = text.substring(1);
			}
			if (text.length() > 0 && (text.startsWith("\n") || text.startsWith("."))) {
				throw new IgnoreMeException();
			}
		}

		return op.apply(leftExpected, rightExpected);
	}

	public MySQLExpression getLeft() {
		return left;
	}

	public MySQLBinaryOperator getOp() {
		return op;
	}

	public MySQLExpression getRight() {
		return right;
	}

}

@@ -18,16 +18,59 @@
 l.ast;%0A%0A
+import java.util.function.BinaryOperator;%0A%0A
 import l
@@ -478,16 +478,545 @@
 ght) %7B%0A%09
+%09%09%09return applyBitOperation(left, right, (l, r) -%3E l & r);%0A%09%09%09%7D%0A%0A%09%09%7D,%0A%09%09OR(%22%7C%22) %7B%0A%09%09%09@Override%0A%09%09%09public MySQLConstant apply(MySQLConstant left, MySQLConstant right) %7B%0A%09%09%09%09return applyBitOperation(left, right, (l, r) -%3E l %7C r);%0A%09%09%09%7D%0A%09%09%7D,%0A%09%09XOR(%22%5E%22) %7B%0A%09%09%09@Override%0A%09%09%09public MySQLConstant apply(MySQLConstant left, MySQLConstant right) %7B%0A%09%09%09%09return applyBitOperation(left, right, (l, r) -%3E l %5E r);%0A%09%09%09%7D%0A%09%09%7D;%0A%0A%09%09private static MySQLConstant applyBitOperation(MySQLConstant left, MySQLConstant right,%0A%09%09%09%09BinaryOperator%3CLong%3E op) %7B%0A
 %09%09%09if (l
@@ -1049,17 +1049,16 @@
 ll()) %7B%0A
-%09
 %09%09%09%09retu
@@ -1099,17 +1099,16 @@
 t();%0A%09%09%09
-%09
 %7D else %7B
@@ -1108,17 +1108,16 @@
  else %7B%0A
-%09
 %09%09%09%09long
@@ -1166,25 +1166,24 @@
 tInt();%0A%09%09%09%09
-%09
 long rightVa
@@ -1226,17 +1226,16 @@
 tInt();%0A
-%09
 %09%09%09%09long
@@ -1247,17 +1247,25 @@
 e = 
+op.apply(
 leftVal
- &
+,
  rig
@@ -1269,19 +1269,19 @@
 rightVal
+)
 ;%0A
-%09
 %09%09%09%09retu
@@ -1335,22 +1335,16 @@
 e);%0A
-%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%7D
 ;%0A%0A%09
@@ -1331,33 +1331,32 @@
 value);%0A%09%09%09%7D%0A%09%09%7D
-;
 %0A%0A%09%09private Stri

Implement the binary or and xor