package ec.gp.syntactic.simplification.logic;

import ec.EvolutionState;
import ec.app.semanticGP.func.logic.And;
import ec.app.semanticGP.func.logic.Or;
import ec.gp.GPNode;
import ec.gp.syntactic.simplification.IRule;
import ec.util.Parameter;

public class OrAndAndRule implements IRule {

	@Override
	public void setup(EvolutionState state, Parameter base) {
		// TODO Auto-generated method stub

	}

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

		if (!(subtree.children[0] instanceof And && subtree.children[1] instanceof And))
			return false;

		return subtree.children[0].children[0].rootedTreeEquals(subtree.children[1].children[0])
				|| subtree.children[0].children[0].rootedTreeEquals(subtree.children[1].children[1])
				|| subtree.children[0].children[1].rootedTreeEquals(subtree.children[1].children[0])
				|| subtree.children[0].children[1].rootedTreeEquals(subtree.children[1].children[1]);
	}

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

		Or or = new Or();
		or.children = new GPNode[2];

		And and = new And();
		and.children = new GPNode[] { null, or };

		if (subtree.children[0].children[0].rootedTreeEquals(subtree.children[1].children[0])) {
			and.children[0] = subtree.children[0].children[0];
			or.children[0] = subtree.children[0].children[1];
			or.children[1] = subtree.children[1].children[1];

			return and;
		}

		if (subtree.children[0].children[0].rootedTreeEquals(subtree.children[1].children[1])) {
			and.children[0] = subtree.children[0].children[0];
			or.children[0] = subtree.children[0].children[1];
			or.children[1] = subtree.children[1].children[0];

			return and;
		}

		if (subtree.children[0].children[1].rootedTreeEquals(subtree.children[1].children[0])) {
			and.children[0] = subtree.children[0].children[1];
			or.children[0] = subtree.children[0].children[0];
			or.children[1] = subtree.children[1].children[1];

			return and;
		}

		if (subtree.children[0].children[1].rootedTreeEquals(subtree.children[1].children[1])) {
			and.children[0] = subtree.children[0].children[1];
			or.children[0] = subtree.children[0].children[0];
			or.children[1] = subtree.children[1].children[0];

			return and;
		}

		throw new UnsupportedOperationException();
	}

}
