package net.heartshield.filter;

import junit.framework.TestCase;

import net.heartshield.signal.CameraUtil;
import net.heartshield.signal.DVec;

import org.apache.commons.math3.analysis.function.Gaussian;
import org.apache.commons.math3.exception.TooManyIterationsException;
import org.apache.commons.math3.fitting.GaussianCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;
import org.jfree.data.xy.XYSeries;

import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

/**
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-11-21
 */
public class ImageProcessingTests extends TestCase {
    public void testLoad() throws IOException, InterruptedException {
        String[] files = "/home/david/heartshield/outsourcing/find_ellipse/example_ellipse1g.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse1.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse2.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse3g.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse3.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse4.png".split(" ");
        BufferedImage img = ImageIO.read(new File(files[0]));

        JFrame frame = new JFrame();
        frame.getContentPane().setLayout(new FlowLayout());
        frame.getContentPane().add(new JLabel(new ImageIcon(img)));
        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // if you want the X button to close the app

        while(frame.isVisible())
            Thread.sleep(1000);
    }

    public void testMean() throws IOException {
        String[] files = "/home/david/heartshield/outsourcing/find_ellipse/example_ellipse1g.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse1.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse2.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse3g.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse3.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse4.png".split(" ");
        BufferedImage img = ImageIO.read(new File(files[0]));

        int[] data = rgb(img);
        //double[][] meanRow = CameraUtil.meanRow(data, img.getWidth(), img.getHeight());
        double[][] meanRow = CameraUtil.meanRow(data, img.getWidth(), img.getHeight());
        double[][] stdRow = CameraUtil.stdRow(data, meanRow, img.getWidth(), img.getHeight());

        double[] redRow = meanRow[0];
        double[] redStdRow = stdRow[0];
        //LineChart lc = LineChart.plot(redRow);

        final XYSeries inSeries = new XYSeries("in");
        final XYSeries outSeries = new XYSeries("out");

        WeightedObservedPoints obs = new WeightedObservedPoints();

        for(int i = 0; i < redRow.length; i++) {
            inSeries.add(i, redRow[i]);
            obs.add(i, redRow[i]);
        }

        // length=3  {Normalization, Mean, Sigma}  see http://commons.apache.org/proper/commons-math/javadocs/api-3.4/org/apache/commons/math3/fitting/GaussianCurveFitter.html
        double[] parameters = GaussianCurveFitter.create().fit(obs.toList());
        System.out.println("parameters.length=" + parameters.length);
        System.out.println("parameters=" + DVec.toString(parameters));

        Gaussian.Parametric p = new Gaussian.Parametric();

        for(int i = 0; i < redRow.length; i++)
            //outSeries.add(i, redRow[i]);
            outSeries.add(i, p.value(i, parameters));

        LineChart lc = new LineChart("brightness", new XYSeries[]{ inSeries, outSeries });

        //LineChart lc = LineChart.plot(filtered);
        lc.showChart();
        lc.waitChart();
    }


    public void testAll() throws IOException {
        String[] files = "/home/david/heartshield/tmp/ue/unellipse_5.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse1g.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse1.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse2.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse3g.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse3.png /home/david/heartshield/outsourcing/find_ellipse/example_ellipse4.png".split(" ");

        for(int j = 0; j < files.length; j++) {
            System.out.println(files[j]);
            BufferedImage img = ImageIO.read(new File(files[j]));

            int[] data = rgb(img);
            //double[][] meanRow = CameraUtil.meanRow(data, img.getWidth(), img.getHeight());
            double[][] meanRow = CameraUtil.meanRow(data, img.getWidth(), img.getHeight());
            double[][] stdRow = CameraUtil.stdRow(data, meanRow, img.getWidth(), img.getHeight());

            double[][] meanCol = CameraUtil.meanCol(data, img.getWidth(), img.getHeight());
            double[][] stdCol = CameraUtil.stdCol(data, meanCol, img.getWidth(), img.getHeight());

            String fn = files[j].split("/")[6];
            showFit(meanRow[0], fn + " row");
            showFit(meanCol[0], fn + " col");
        }
    }

    private void showFit(double[] x, String title) {

        final XYSeries inSeries = new XYSeries("in");
        final XYSeries outSeries = new XYSeries("out");

        WeightedObservedPoints obs = new WeightedObservedPoints();

        for (int i = 0; i < x.length; i++) {
            double v = x[i];
            inSeries.add(i, v);
            obs.add(i, v);
        }

        System.out.println("x=" + DVec.toString(x));
        LineChart lc2 = LineChart.plot(DVec.add(x, -250.0));
        lc2.showChart();
        lc2.waitChart();

        // length=3  {Normalization, Mean, Sigma}  see http://commons.apache.org/proper/commons-math/javadocs/api-3.4/org/apache/commons/math3/fitting/GaussianCurveFitter.html
        System.out.println("fitting...");
        // LevenbergMarquardtOptimizer may get stuck underneath this.
        //double[] parameters = GaussianCurveFitter.create().fit(obs.toList());
        double[] parameters = null;
        try {
            //parameters = GaussianCurveFitter.create().withStartPoint(new double[]{norm,mean,std}).withMaxIterations(800).fit(obs.toList());
            parameters = GaussianCurveFitter.create().withMaxIterations(800).fit(obs.toList());
            System.out.println("done.");
        } catch(TooManyIterationsException e) {
            System.out.println("timed out.");
            return;
        }

        Gaussian.Parametric p = new Gaussian.Parametric();

        for (int i = 0; i < inSeries.getItemCount(); i++)
            //outSeries.add(i, redRow[i]);
            outSeries.add(i, p.value(i, parameters));

        LineChart lc = new LineChart(title, new XYSeries[]{inSeries, outSeries});

        //LineChart lc = LineChart.plot(filtered);
        lc.showChart();
        lc.waitChart();
    }

    private int[] rgb(BufferedImage image) {
        int[] data = new int[image.getWidth()*image.getHeight()];
        for(int j = 0, yp = 0; j < image.getHeight(); j++)
            for(int i = 0; i < image.getWidth(); i++, yp++)
                data[yp] = image.getRGB(i, j);
        return data;
    }

    // CameraUtil
    // double[][] meanCol(int[] rgb, int width, int height)
}
