package ec.gp.syntactic.simplification.numeric;

import ec.EvolutionState;
import ec.app.semanticGP.func.numeric.Constant;
import ec.app.semanticGP.func.numeric.Mul;
import ec.app.semanticGP.func.numeric.Pow;
import ec.gp.GPNode;
import ec.gp.syntactic.simplification.IRule;
import ec.util.Parameter;

class MulMulRule 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 Mul))
			return false;

		if (subtree.children[0] instanceof Mul) {
			return subtree.children[0].children[0].rootedTreeEquals(subtree.children[0].children[1])
					&&
					subtree.children[0].children[0].rootedTreeEquals(subtree.children[1]);
		} else if (subtree.children[1] instanceof Mul) {
			return subtree.children[1].children[0].rootedTreeEquals(subtree.children[1].children[1])
					&&
					subtree.children[1].children[0].rootedTreeEquals(subtree.children[0]);
		}

		return false;
	}

	@Override
	public GPNode replace(GPNode subtree) {
		assert match(subtree) : "The given tree is not a form of ((p * p) * p) or (p * (p * p))";

		Constant constant = Constant.THREE;
		Pow pow = new Pow();

		if (subtree.children[0] instanceof Mul) {

			pow.children = new GPNode[] { subtree.children[1], constant };
			return pow;

		} else if (subtree.children[1] instanceof Mul) {

			pow.children = new GPNode[] { subtree.children[0], constant };
			return pow;

		}

		throw new UnsupportedOperationException("The given tree is not a forms of ((p * p) * p) or (p * (p * p))");
	}

}
