package ec.gp.semantic.geometry;

import ec.EvolutionState;
import ec.app.semanticGP.func.logic.*;
import ec.gp.GPNode;
import ec.gp.semantic.func.SimpleNodeBase;
import ec.gp.semantic.utils.InstructionJoiner;
import ec.util.Parameter;
import library.semantics.TestCase;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Tomasz Pawlak
 */
public class BooleanInterpolator implements IInterpolator<Boolean> {
	private static final Parameter DEFAULT_BASE = new Parameter("BooleanInterpolator");

	protected Parameter defaultBase() {
		return DEFAULT_BASE;
	}

	public List<SimpleNodeBase<?>> getBasePrograms(EvolutionState state, List<TestCase<Boolean>> points) {
		return this.getBasePrograms(state, points, false);
	}

	public List<SimpleNodeBase<?>> getBasePrograms(EvolutionState state, List<TestCase<Boolean>> points, boolean addNegative) {
		List<SimpleNodeBase<?>> programs = new ArrayList<SimpleNodeBase<?>>(points.size());

		for (TestCase<Boolean> tc : points) {

			if (!addNegative && !tc.getValue()) {
				continue;
			}

			Boolean[] arguments = tc.getArguments();
			List<SimpleNodeBase<?>> toJoin = new ArrayList<SimpleNodeBase<?>>();
			SimpleNodeBase<Boolean> newTerm = null;

			for (int i = 0; i < arguments.length; ++i) {
				newTerm = InputN.get((byte) i);

				if (!arguments[i]) {
					Inv inv = new Inv();
					inv.children = new GPNode[]{newTerm};
					newTerm = inv;
				}

				toJoin.add(newTerm);
			}

			programs.add(InstructionJoiner.join(toJoin, And.class, 2));
		}

		if (programs.isEmpty()) {
			programs.add(Constant.get(false));
		}

		return programs;
	}

	@Override
	public SimpleNodeBase<Boolean> getProgram(EvolutionState state, List<TestCase<Boolean>> points) {
		List<SimpleNodeBase<?>> programs = this.getBasePrograms(state, points);
		SimpleNodeBase<?> program = InstructionJoiner.join(programs, Or.class, 2);

		return (SimpleNodeBase<Boolean>) program;
	}
}
