package ec.gp.semantic.initialization;

import ec.EvolutionState;
import ec.gp.*;
import ec.gp.semantic.ISemanticProblem;
import ec.gp.semantic.ISemantics;
import ec.gp.semantic.func.SimpleNodeBase;
import ec.gp.semantic.geometry.IBallBuilder;
import ec.gp.semantic.geometry.IInterpolator;
import ec.util.Parameter;
import ec.util.ParameterDatabase;
import library.semantics.TestCase;

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

/**
 * Semantic Geometric Initialization.
 *
 * @author Tomasz Pawlak
 */
public class SGI extends GPNodeBuilder {
	private final static Parameter DEFAULT_BASE = new Parameter("SGI");
	private final static String INTERPOLATOR = "interpolator";
	private final static String BALL_BUILDER = "ballBuilder";

	private EvolutionState state;
	private IInterpolator<?> interpolator;
	private IBallBuilder ballBuilder;
	private Iterator<ISemantics> ball;
	private ISemantics target;
	private List<TestCase> fitnessCases;

	@Override
	public Parameter defaultBase() {
		return DEFAULT_BASE;
	}

	@Override
	public void setup(EvolutionState state, Parameter base) {
		super.setup(state, base);

		this.state = state;

		ParameterDatabase db = state.parameters;
		this.interpolator = (IInterpolator<?>) db.getInstanceForParameter(base.push(INTERPOLATOR), defaultBase().push(INTERPOLATOR), IInterpolator.class);
		this.ballBuilder = (IBallBuilder) db.getInstanceForParameter(base.push(BALL_BUILDER), defaultBase().push(BALL_BUILDER), IBallBuilder.class);
	}

	@Override
	public GPNode newRootedTree(EvolutionState state, GPType type, int thread, GPNodeParent parent, GPFunctionSet set, int argposition, int requestedSize) {
		if (this.target == null) {
			ISemanticProblem<?> problem = (ISemanticProblem<?>) state.evaluator.p_problem;

			this.target = problem.getTargetSemantics();
			this.fitnessCases = (List) problem.getFitnessCases();
			this.ball = this.ballBuilder.getPointsAround(this.target, 1.0);
		}

		ISemantics expectedSemantics = this.ball.next();
		List<TestCase> points = new ArrayList<>(expectedSemantics.size());
		for (int i = 0; i < expectedSemantics.size(); ++i) {
			TestCase tc = new TestCase();
			tc.setArguments(this.fitnessCases.get(i).getArguments());
			tc.setValue(expectedSemantics.getValue(i));
			points.add(tc);
		}
		SimpleNodeBase<?> program = this.interpolator.getProgram(state, (List) points);
		//assert expectedSemantics.distanceTo(program.getSemantics()) < 1 : expectedSemantics.distanceTo(program.getSemantics());
		return program;
	}


}
