package ac.essex.gp.ooechs.novelty1;

import ac.essex.ooechs.imaging.commons.signal.Signal;
import ac.essex.ooechs.imaging.commons.signal.SignalProcessor;
import ac.essex.ooechs.imaging.commons.PixelLoader;
import ac.essex.ooechs.imaging.commons.ColourChannels;
import ac.essex.ooechs.imaging.commons.StatisticsSolver;
import ac.essex.gp.ooechs.novelty1.nodes.functions.*;
import ac.essex.gp.ooechs.novelty1.nodes.terminals.VectorTerminal;
import ac.essex.gp.problems.Problem;
import ac.essex.gp.problems.DataStack;
import ac.essex.gp.Evolve;
import ac.essex.gp.nodes.ercs.*;
import ac.essex.gp.nodes.Add;
import ac.essex.gp.nodes.Sub;
import ac.essex.gp.nodes.logic.Less;
import ac.essex.gp.nodes.logic.Equals;
import ac.essex.gp.nodes.logic.More;
import ac.essex.gp.individuals.Individual;
import ac.essex.gp.params.GPParams;
import ac.essex.gp.params.NodeConstraints;
import ac.essex.gp.interfaces.graphical.GraphicalListener;

import java.io.File;
import java.util.Vector;

/**
 * <p/>
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version,
 * provided that any use properly credits the author.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details at http://www.gnu.org
 * </p>
 *
 * @author Olly Oechsle, University of Essex, Date: 16-Apr-2008
 * @version 1.0
 */
public class NovelGPProblem extends Problem {

    public static final int TRUE = 1;
    public static final int FALSE = 2;

    protected Vector<Signal> data;

    protected int channel, statistic;

    public static int maxSignal = 255;
    public static int signalLength;

    public static SignalProcessor currentSignal;

    public static void main(String[] args) {
        NovelGPProblem problem = new NovelGPProblem(ColourChannels.GREYSCALE, StatisticsSolver.MEAN);
        problem.load("/home/ooechs/Desktop/pipes/Foreground/", TRUE);
        problem.load("/home/ooechs/Desktop/pipes/Background/", FALSE);
        Evolve e = new Evolve(problem, new GraphicalListener());
        e.start();
    }

    public NovelGPProblem(int channel, int statistic) {
        data = new Vector<Signal>();
        this.channel = channel;
        this.statistic = statistic;
    }

    public void load(String directoryPath, int classID) {

        File directory = new File(directoryPath);
        if (directory.exists() && directory.isDirectory()) {

            File[] files = directory.listFiles();

            for (int i = 0; i < files.length; i++) {
                File imageFile = files[i];
                try {
                    PixelLoader image = new PixelLoader(imageFile);

                    Signal s = new Signal(channel, statistic, image);

                    s.classID = classID;

                    data.add(s);

                    signalLength = s.data.length;

                } catch (Exception err) {
                    // don't worry too much
                }
            }

        }

        System.out.println("Loaded " + data.size() + " files");

    }


    public String getName() {
        return "Novel GP Problem";
    }

    public void initialise(Evolve evolve, GPParams params) {

        params.registerNode(new Add());
        params.registerNode(new Sub());

        params.registerNode(new BoolERC());
        params.registerNode(new Less());
        params.registerNode(new More());
        params.registerNode(new Equals());

        params.registerNode(new Count());
        params.registerNode(new GetHeightRange());
        params.registerNode(new GetMaxWidth());
        params.registerNode(new GetMinWidth());

        // functions which return vectors
        params.registerNode(new GetPeaks());
        params.registerNode(new GetTroughs());

        // the obligatory terminal for vector types
        params.registerNode(new VectorTerminal());

        // parameters for the get peaks/troughs methods
        params.registerNode(new PercentageERC(NodeConstraints.PARAMETER));

        // erc for any comparison or mathematical functions
        params.registerNode(new SmallIntERC());

        params.setReturnType(NodeConstraints.BOOLEAN);

    }

    public void customiseParameters(GPParams gpParams) {
        // Do nothing for the moment
    }

    public void evaluate(Individual individual, DataStack dataStack, Evolve evolve) {

        int totalFalseData = 0;
        int totalTrueData = 0;

        int trueHits = 0;
        int falseHits = 0;

        for (int i = 0; i < data.size(); i++) {
            Signal signal = data.elementAt(i);  

            currentSignal = new SignalProcessor(signal);

            boolean returnedTrue = individual.execute(dataStack) > 0;

            if (signal.classID == TRUE)  {
                totalTrueData++;
                if (returnedTrue) trueHits++;
            } else {
                totalFalseData++;
                if (returnedTrue) falseHits++;
            }

        }

        double truePercentage = trueHits / (double) totalTrueData;
        double falsePercentage = falseHits / (double) totalFalseData;
        double x = 1;

        double fitness = x * (1 - truePercentage) + falsePercentage;

        individual.setKozaFitness(fitness);
        individual.setHits(trueHits);
        individual.setMistakes(falseHits);

    }

}
