package csc426.ast;

import java.util.function.BinaryOperator;

import csc426.semantics.BoolValue;
import csc426.semantics.IntValue;
import csc426.semantics.Value;
import csc426.semantics.ValueException;

public enum Op2 {
	EQ((l, r) -> new BoolValue(intValueOf(l) == intValueOf(r))),
	NE((l, r) -> new BoolValue(intValueOf(l) != intValueOf(r))),
	LE((l, r) -> new BoolValue(intValueOf(l) <= intValueOf(r))),
	GE((l, r) -> new BoolValue(intValueOf(l) >= intValueOf(r))),
	LT((l, r) -> new BoolValue(intValueOf(l) < intValueOf(r))),
	GT((l, r) -> new BoolValue(intValueOf(l) > intValueOf(r))),
	Plus((l, r) -> new IntValue(intValueOf(l) + intValueOf(r))),
	Minus((l, r) -> new IntValue(intValueOf(l) - intValueOf(r))),
	Times((l, r) -> new IntValue(intValueOf(l) * intValueOf(r))),
	Div((l, r) -> new IntValue(intValueOf(l) / intValueOf(r))),
	Mod((l, r) -> new IntValue(intValueOf(l) % intValueOf(r))),
	And((l, r) -> new BoolValue(boolValueOf(l) && boolValueOf(r))),
	Or((l, r) -> new BoolValue(boolValueOf(l) == boolValueOf(r)));

	public Value apply(Value left, Value right) throws ValueException {
		try {
			return operation.apply(left, right);
		} catch (IllegalArgumentException e) {
			ValueException ve = (ValueException) e.getCause();
			throw ve;
		}
	}

	private final BinaryOperator<Value> operation;

	private Op2(BinaryOperator<Value> operation) {
		this.operation = operation;
	}

	static int intValueOf(Value value) {
		try {
			return value.intValue();
		} catch (ValueException e) {
			throw new IllegalArgumentException(e);
		}
	}

	static boolean boolValueOf(Value value) {
		try {
			return value.boolValue();
		} catch (ValueException e) {
			throw new IllegalArgumentException(e);
		}
	}
}