package ec.app.semanticGP.func.logic;

import library.semantics.*;
import ec.*;
import ec.app.semanticGP.func.*;
import ec.gp.semantic.*;
import ec.gp.semantic.evaluation.*;
import ec.gp.semantic.func.*;

public class Combiner extends CombinerBase<Boolean> {

	public Combiner(EvolutionState state, SimpleNodeBase<Boolean> parent1, SimpleNodeBase<Boolean> parent2,
					SimpleNodeBase<Boolean> randomTree) {
		super(state, parent1, parent2, randomTree);
	}

	public Combiner(EvolutionState state, SimpleNodeBase[] parents, SimpleNodeBase[] randomTrees) {
		super(state, parents, randomTrees);
	}

	@Override
	public ISemantics getSemantics() {
		EvaluationMode mode = EvaluationMode.TrainingSet;
		if (this.state.evaluator.p_problem instanceof IChangeableEvaluationMode) {
			((IChangeableEvaluationMode) this.state.evaluator.p_problem).getEvaluationMode();
		}

		ISemantics semantics = this.semantics.get(mode);
		if (semantics == null) {
			BitSet[] p = new BitSet[this.firstRandomTree];
			BitSet[] r = new BitSet[this.children.length - this.firstRandomTree];
			for (int i = 0; i < this.firstRandomTree; ++i) {
				p[i] = (BitSet) ((SimpleNodeBase<?>) this.children[i]).getSemantics().getValue();
			}
			for (int i = this.firstRandomTree; i < this.children.length; ++i) {
				r[i - this.firstRandomTree] = (BitSet) ((SimpleNodeBase<?>) this.children[i]).getSemantics().getValue();
			}

			int maxMask = 1 << r.length;
			BitSet mySem = (BitSet) p[0].clone();
			mySem.clear();

			/// mask%parents.length == number of current parent
			for (int mask = 0; mask < maxMask; ++mask) {
				for (int i = 0; i < mySem.length(); ++i) {

					boolean mult = true;
					for (int b = 0; b < r.length; ++b) {
						// equivalent to:
						// mult &= (((mask >>> b) & 1) == 1 ? r[b].get(i) : !r[b].get(i));
						// but without branching
						assert (((mask >>> b) & 1) == 1 ? r[b].get(i) : !r[b].get(i)) == !((((mask >>> b) & 1) == 1) ^ r[b].get(i));
						mult &= !((((mask >>> b) & 1) == 1) ^ r[b].get(i));
					}

					mySem.set(i, mySem.get(i) | p[mask % p.length].get(i) & mult);
				}
			}


			semantics = new BooleanSemantics(mySem);
			this.semantics.put(mode, semantics);
		}

		return semantics;
	}
}
