package ec.gp.semantic.initialization;

import ec.EvolutionState;
import ec.gp.*;
import ec.gp.semantic.DesiredSemanticsBase;
import ec.gp.semantic.EvoState;
import ec.gp.semantic.ISemanticProblem;
import ec.gp.semantic.library.ILibrary;
import ec.util.Parameter;
import library.space.SearchResult;

import java.util.List;

/**
 * Fills initial population with popSize most (or least) similar programs from the library.
 *
 * @author Tomasz Pawlak
 */
public class SemanticNodeBuilder extends GPNodeBuilder {

    private final static Parameter DEFAULT_BASE = new Parameter("SemanticNodeBuilder");
    protected ILibrary<?> library;
    protected EvolutionState state;
    protected double[] targetSemantics;
    private List<SearchResult<GPNode>> sortedIndividuals;
    private int indIndex = 0;

    /**
     * Start from most (true) or least (false) similar programs.
     */
    private boolean mostSimilar = true;

    //protected GeometricDistribution randomGenerator;

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

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

        this.state = state;
        this.library = ((EvoState) state).getLibrary();

		/*randomGenerator = new GeometricDistribution();
        randomGenerator.setup(state, base);*/

        if (!mostSimilar) {
            indIndex = library.size() - 1;
        }
    }

    @Override
    public GPNode newRootedTree(final EvolutionState state, final GPType type, final int thread,
                                final GPNodeParent parent, final GPFunctionSet set, final int argposition, final int requestedSize) {

        if (targetSemantics == null) {
            targetSemantics = (double[]) ((ISemanticProblem) state.evaluator.p_problem).getTargetSemantics().getValue();
            sortedIndividuals = library.getPrograms(new DesiredSemanticsBase(targetSemantics), new DesiredSemanticsBase[0], library.size(), requestedSize);
        }

        GPNode ind = null;
        if (mostSimilar) {
            ind = sortedIndividuals.get(indIndex++).getProgram();
            indIndex = (indIndex + 1) % sortedIndividuals.size();
        } else {
            ind = sortedIndividuals.get(indIndex--).getProgram();
            if (indIndex < 0)
                indIndex = sortedIndividuals.size() - 1;
        }
        return ind;
    }

}
