package ac.essex.ooechs.facedetection.evolved.ga;

import ga.core.GAProblem;
import ga.core.GAIndividual;
import ga.Evolve;
import ga.listeners.GAConsoleListener;
import ac.essex.ooechs.imaging.commons.StatisticsSolver;
import ac.essex.ooechs.imaging.commons.util.FileIO;
import ac.essex.ooechs.facedetection.util.DataSet;
import ac.essex.ooechs.facedetection.util.IntegralTrainingImage;
import ac.essex.ooechs.facedetection.evolved.ga.genes.HeightGene;
import ac.essex.ooechs.facedetection.evolved.ga.genes.WidthGene;
import ac.essex.ooechs.facedetection.evolved.ga.genes.XGene;
import ac.essex.ooechs.facedetection.evolved.ga.genes.YGene;
import ac.essex.ooechs.facedetection.evolved.ga.GAFeatureIndividual;

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


public class GAFeatureFinder extends GAProblem {

    protected DataSet training;
    protected File saveTo;
    protected int mode;
    protected static int counter = 1;
    protected static String prefix = "";

    public static void main(String[] args) throws Exception {

        // Face Detection
/*        DataSet dataSet = new DataSet("/home/ooechs/Data/faces/train/face/", "/home/ooechs/Data/faces/train/non-face");
        File saveTo  = new File("/home/ooechs/FaceDetection/src/ac/essex/ooechs/facedetection/evolved/evolved/evolved_face/");
        int width = 20;
        int height = 20;
        int xStep = 6;
        int yStep = 6;*/
        // End

        // Pipe Detection
        String packageName = "evolved_pipes";
        DataSet dataSet = new DataSet("/home/ooechs/Desktop/pipe-images2/foreground", "/home/ooechs/Desktop/pipe-images2/background");
        File saveTo  = new File("/home/ooechs/FaceDetection/src/ac/essex/ooechs/facedetection/evolved/ga/results/" + packageName + "/");
        int width = 20;
        int height = 19;
        int xStep = 5;
        int yStep = 5;
        prefix = "pipes_";
        // End

        if (!saveTo.exists()) saveTo.mkdirs();


        for (int mode = GAFeatureIndividual.TWO_RECT; mode <= GAFeatureIndividual.FOUR_RECT; mode++) {

            counter = 0;

            for (int x = 1; x < width; x+=xStep) {
                for (int y = 1; y < height; y+=yStep) {
                    new Evolve(new GAFeatureFinder(dataSet, saveTo, mode, x, y, xStep, yStep), new GAConsoleListener(true)).run();
                }
            }

        }

    }

    public GAFeatureFinder(DataSet dataSet, File saveTo, int mode, int x, int y, int width, int height)  {
        this.training = dataSet;
        this.saveTo = saveTo;
        this.mode = mode;
        GAFeatureIndividual.startX = x;
        GAFeatureIndividual.startY = y;
        WidthGene.maxValue = width*2;
        HeightGene.maxValue = height*2;
        XGene.max = width;
        YGene.max = height;
    }

    public void bruteForceSearch() {

        double lowest = Double.MAX_VALUE;
        double highest = Double.MIN_VALUE;

        Vector<IntegralTrainingImage> trainingData = training.getData();

        StatisticsSolver f1 = new StatisticsSolver();

        // for every x
        for (int x = 0; x < 20; x++)
        // for every y
        for (int y = 0; y < 20; y++)
        // for every width
        for (int w = 1; w < 20; w++)
        // for every height
        for (int h = 1; h < 20; h++)

        for (int a = 1; a <=2; a++) {

            StatisticsSolver f = new StatisticsSolver();

            // for every adjacency
             for (int i = 0; i < trainingData.size(); i++) {
                IntegralTrainingImage integralTrainingImage = trainingData.elementAt(i);
                if (integralTrainingImage.classID == DataSet.TRUE) {
                    double result = integralTrainingImage.getImage().getHaarlikeFeatures().getTwoRectangleFeature(x,y,w,h,a);
                    f.addData((float) result);
                }
            }

            double mean = f.getMean();
            double fitness = f.getStandardDeviation();



            if (mean == 0 || fitness == 0) continue;
            f1.addData(fitness);


            if (fitness < lowest) {
                lowest = fitness;
                System.out.println("Lowest: " + lowest);
            }

            if (fitness > highest)  {
                highest = fitness;
                System.out.println("Highest: " + highest);
            }


        }

        System.out.println("f1 Mean " + f1.getMean());
        System.out.println("f1 Std Dev: " + f1.getStandardDeviation());



    }

    public String getName() {
        return "Face Feature Finder";
    }

    public GAIndividual createIndividual() {
        return new GAFeatureIndividual(GAFeatureIndividual.FOUR_RECT);
    }

    public void evaluate(GAIndividual ind) {

        Vector<IntegralTrainingImage> trainingData = training.getData();

        StatisticsSolver f = new StatisticsSolver();

        for (int i = 0; i < trainingData.size(); i++) {
            IntegralTrainingImage integralTrainingImage = trainingData.elementAt(i);
            if (integralTrainingImage.classID == DataSet.TRUE) {
                double result = ind.execute(integralTrainingImage.getImage());
                f.addData((float) result);
            }
        }

        double mean = f.getMean();
        double fitness = f.getStandardDeviation();
        
        if (fitness == 0 || mean == 0) ind.setWorstFitness();

        else ind.setKozaFitness(fitness);
    }


    public void onFinish(GAIndividual gaIndividual) {
        System.out.println(gaIndividual.toJava());
        System.out.println(gaIndividual.getKozaFitness());

        StringBuffer buffer = new StringBuffer();
        String className = null;
        switch (mode) {
            case GAFeatureIndividual.TWO_RECT:
                className = "TwoRectFeature" + counter;
                break;
            case GAFeatureIndividual.THREE_RECT:
                className = "ThreeRectFeature" + counter;
                break;
            case GAFeatureIndividual.FOUR_RECT:
                className = "FourRectFeature" + counter;
                break;
        }
        className = prefix + className;

        buffer.append("package ac.essex.ooechs.facedetection.evolved.ga.results." + saveTo.getName() + ";\n");
        buffer.append("import ac.essex.ooechs.facedetection.evolved.EvolvedFeature;\n" +
                "import ac.essex.ooechs.imaging.commons.fast.IntegralImage;\n\n");
        buffer.append("/*\n* Fitness: ");
        buffer.append(gaIndividual.getKozaFitness());
        buffer.append("\n*/\n");
        buffer.append("public class ");
        buffer.append(className);
        buffer.append(" extends EvolvedFeature {\n\n");
        buffer.append("public double eval(IntegralImage image) {\nreturn ");
        buffer.append(gaIndividual.toJava());
        buffer.append(";\n}\n}");

        try {
            FileIO.saveToFile(buffer.toString(), new File(saveTo, className + ".java"));
            System.out.println("Classname: " + className);
            counter++;
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}