package gp;

import java.util.Random;
import java.util.Vector;

public class EvolutionaryAlgorithm implements AlgorithmInterface {
	boolean bStop;
	EaGuiCallback gcb = null;
	int mu, tMax;
	SelectionEnum selMethod;
	double pCross, pMut, selParam;

	public EvolutionaryAlgorithm(EaGuiCallback g) {
		gcb = g;
	}

	@Override
	public void setCallback(EaGuiCallback g) {
		gcb = g;
	}

	@Override
	public void start(int muu, int tmax, double pcross, double pmut,
			SelectionEnum selM, double selP) {
		mu = muu;
		tMax = tmax;
		selMethod = selM;
		pCross = pcross;
		pMut = pmut;
		selParam = selP;
		(new Thread(this)).start();
	}

	@Override
	public void stop() {
		bStop = true;
	}

	protected void initIndividuals(InterfaceIndividual[] indies) {
		for (int i = 0; i < indies.length; i++) {
			// allocate and init starting population
			// indies[i] = new DummyGPIndividual(6, GPTree.MODE_GROW);
			// TODO: Replace with RegrIndividual
			indies[i] = new RegrIndividual(6, GPTree.MODE_GROW);
			indies[i].defaultInit();
		}
	}

	@Override
	public void run() {
		int i, j, t = 1;
		Random rand = new Random();
		InterfaceIndividual[] parents = new InterfaceIndividual[mu];
		InterfaceIndividual[] offsprings = new InterfaceIndividual[mu];

		initIndividuals(parents);

		InterfaceIndividual best;
		Selection selection = new Selection(selMethod, selParam, rand, gcb);
		Vector<InterfaceIndividual> matingPool;
		long lastMillis = System.currentTimeMillis();

		bStop = false;
		while (!bStop) {
			if (System.currentTimeMillis() > (lastMillis + 500)) {
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
				}
			}

			try {
				matingPool = selection.generateMatingPool(parents); // Selection

				for (i = 0; i < mu; i++) // Replication
				{
					j = rand.nextInt(matingPool.size());
					offsprings[i] = (InterfaceIndividual) (matingPool
							.elementAt(j)).clone();
					matingPool.removeElementAt(j);
				}

				for (i = 0; i < (mu - 1); i += 2) {
					if (rand.nextDouble() < pCross) {
						offsprings[i].crossover(offsprings[i + 1]);
					}
				}

				for (i = 0; i < mu; i++) {
					offsprings[i].mutate(pMut); // Mutation
				}

				parents = offsprings.clone();
			} catch (Exception e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
				bStop = true;
			}
			if ((t++) >= tMax) {
				bStop = true;
			}
		}

		best = selection.findBest(parents);
		if (gcb != null) {
			gcb.algoStop(best);
		}
		// if ((gcb != null) && (best instanceof RegrIndividualSol)) {
		// gcb.clearFun();
		// gcb.plotFun(((RegrIndividualSol) best).trueFct());
		// gcb.plotFun(((RegrIndividualSol) best).regFct());
		// }
		if (gcb == null) {
			System.out.println(best.getStringRepresentation());
		}
	}
}
