package ec.app.semanticGP.func.numeric;

import java.util.Arrays;
import java.util.List;

import library.semantics.TestCase;
import ec.EvolutionState;
import ec.app.semanticGP.func.IConstant;
import ec.gp.GPNode;
import ec.gp.semantic.DoubleSemantics;
import ec.gp.semantic.ISemanticProblem;
import ec.gp.semantic.ISemantics;
import ec.gp.semantic.func.NullaryNode;
import ec.util.Parameter;

public final class ERC extends NullaryNode<Double> implements IConstant<Double> {

	private ISemantics semantics;

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

	@Override
	public void resetNode(EvolutionState state, int thread) {
		super.resetNode(state, thread);
		resetNode(this.state.random[0].nextDouble() * 2.0 - 1.0);
	}

	protected void resetNode(double constant) {
		ISemanticProblem<Double> problem = (ISemanticProblem<Double>) this.state.evaluator.p_problem;
		List<TestCase<Double>> cases = problem.getFitnessCases();

		double[] semantics = new double[cases.size()];
		Arrays.fill(semantics, constant);

		this.semantics = new DoubleSemantics(semantics);
	}

	@Override
	public String toString() {
		if (this.semantics != null)
			return this.semantics.getValue(0).toString();
		return "ERC";
	}

	@Override
	protected ISemantics execute(ISemantics... arguments) {
		ISemanticProblem<Double> problem = (ISemanticProblem<Double>) this.state.evaluator.p_problem;
		List<TestCase<Double>> cases = problem.getFitnessCases();

		if (this.semantics == null) {
			this.resetNode(this.state, 0);
		} else if (((double[]) this.semantics.getValue()).length != cases.size()) {
			this.resetNode((double) this.semantics.getValue(0));
		}
		return this.semantics;
	}

	@Override
	public int nodeHashCode() {
		return this.getConstant().hashCode();
	}

	@Override
	public boolean nodeEquals(GPNode node) {
		if (!(node instanceof IConstant))
			return false;

		IConstant<Double> other = (IConstant<Double>) node;
		return this.getConstant() == other.getConstant();
	}

	@Override
	public Double getConstant() {
		return (Double) this.semantics.getValue(0);
	}

}
