package ec.gp.syntactic.simplification.numeric;

import ec.EvolutionState;
import ec.app.semanticGP.func.IConstant;
import ec.app.semanticGP.func.numeric.Constant;
import ec.app.semanticGP.func.numeric.Sub;
import ec.app.semanticGP.func.numeric.Sum;
import ec.gp.GPNode;
import ec.gp.syntactic.simplification.IRule;
import ec.util.Parameter;

class SubSubTwoConstRule implements IRule {

	private EvolutionState state;

	@Override
	public void setup(EvolutionState state, Parameter base) {
		this.state = state;
	}

	@Override
	public boolean match(GPNode subtree) {
		if (!(subtree instanceof Sub))
			return false;

		if (subtree.children[0] instanceof Sub) {
			return subtree.children[1] instanceof IConstant
					&&
					(subtree.children[0].children[0] instanceof IConstant || subtree.children[0].children[1] instanceof IConstant);
		} else if (subtree.children[1] instanceof Sub) {
			return subtree.children[0] instanceof IConstant
					&&
					(subtree.children[1].children[0] instanceof IConstant || subtree.children[1].children[1] instanceof IConstant);
		}

		return false;
	}

	@Override
	public GPNode replace(GPNode subtree) {
		assert subtree instanceof Sub : "The given tree is not a form of (p - c1) - c2 or (c1 - p) - c2 or c1 - (c2 - p) or c1 - (p - c2)";

		if (subtree.children[0] instanceof Sub) {
			if (subtree.children[0].children[0] instanceof IConstant) {
				double v1 = ((IConstant<Double>) subtree.children[0].children[0]).getConstant();
				double v2 = ((IConstant<Double>) subtree.children[1]).getConstant();
				Constant c = new Constant(v1 - v2);
				Sub sub = new Sub();
				sub.children = new GPNode[] { c, subtree.children[0].children[1] };

				return sub;
			} else if (subtree.children[0].children[1] instanceof IConstant) {
				double v1 = ((IConstant<Double>) subtree.children[0].children[1]).getConstant();
				double v2 = ((IConstant<Double>) subtree.children[1]).getConstant();
				Constant c = new Constant(v1 + v2);
				Sub sub = new Sub();
				sub.children = new GPNode[] { subtree.children[0].children[0], c };

				return sub;
			}
		} else if (subtree.children[1] instanceof Sub) {
			if (subtree.children[1].children[0] instanceof IConstant) {
				double v1 = ((IConstant<Double>) subtree.children[0]).getConstant();
				double v2 = ((IConstant<Double>) subtree.children[1].children[0]).getConstant();
				Constant c = new Constant(v1 - v2);
				Sum sum = new Sum();
				sum.children = new GPNode[] { c, subtree.children[1].children[1] };

				return sum;
			} else if (subtree.children[1].children[1] instanceof IConstant) {
				double v1 = ((IConstant<Double>) subtree.children[0]).getConstant();
				double v2 = ((IConstant<Double>) subtree.children[1].children[1]).getConstant();
				Constant c = new Constant(v1 + v2);
				Sub sub = new Sub();
				sub.children = new GPNode[] { c, subtree.children[1].children[0] };

				return sub;
			}
		}

		throw new UnsupportedOperationException(
				"The given tree is not a form of (p - c1) - c2 or (c1 - p) - c2 or c1 - (c2 - p) or c1 - (p - c2)");
	}
}
