import ChartDirector.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.io.File;
import java.util.Collections;

/**
 * Zeigt das Fenster an mit allen Komponenten
 * 
 * @author Alexander Kimmig 
 * @version 1.0
 */
public class Window implements ActionListener
{
    private JFrame frame;
    private JPanel drawPanel;
    
    private ArrayList<RGB> image;
    private ArrayList<RGB> orig;
    private ArrayList<RGB> quants;
    
    private int alpha = 25;
    private int beta = 45;
    
    private JButton vl;
    private JButton vr;
    private JButton vu;
    private JButton vd;
    
    private JButton b_load;
    private JButton b_gen;
    private JButton b_epoc;
    private JButton b_reset;
    private JButton b_save;

    private JComboBox s_input;
    private JTextField t_anz;
    private JTextField t_output;
    
    /**
     * Konstruktor: legt JFrame und alle Panels/Buttons an
     */
    public Window()
    {
        frame = new JFrame();
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) { System.exit(0); }
        });
        
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        
        drawPanel = new JPanel();
        drawPanel.setPreferredSize(new Dimension(1000, 1000));
        drawPanel.setBackground(new Color(0xFFFFFF));
        JPanel view = new JPanel();
        JPanel steps = new JPanel();
        JPanel config = new JPanel();

        mainPanel.add(drawPanel);
        mainPanel.add(view);
        mainPanel.add(steps);
        mainPanel.add(config);
        
        vl = new JButton("<");
        vl.addActionListener(this);
        view.add(vl);
        vr = new JButton(">");
        vr.addActionListener(this);
        view.add(vr);
        vu = new JButton("^");
        vu.addActionListener(this);
        view.add(vu);
        vd = new JButton("v");
        vd.addActionListener(this);
        view.add(vd);
        
        b_load = new JButton("Datei laden");
        b_load.addActionListener(this);
        steps.add(b_load);
        
        b_gen = new JButton("Zufällige Punkte erzeugen");
        b_gen.addActionListener(this);
        steps.add(b_gen);

        b_epoc = new JButton("Epoche durchspielen");
        b_epoc.addActionListener(this);
        steps.add(b_epoc);

        b_reset = new JButton("Punkte versetzen");
        b_reset.addActionListener(this);
        steps.add(b_reset);
        
        b_save = new JButton("Datei speichern");
        b_save.addActionListener(this);
        steps.add(b_save);
        
        config.add(new JLabel("Input:"));
        s_input = new JComboBox(getJPGs());
        config.add(s_input);

        config.add(new JLabel("Anzahl Punkte:"));
        t_anz = new JTextField("32");
        t_anz.setPreferredSize(new Dimension(100,20));
        config.add(t_anz);

        config.add(new JLabel("Output:"));
        t_output = new JTextField("output.jpg");
        t_output.setPreferredSize(new Dimension(100,20));
        config.add(t_output);

        frame.add(mainPanel);

        frame.pack();
        frame.setVisible(true);
        
        this.image = new ArrayList<>();
        this.quants = new ArrayList<>();
        
        this.plot();
    }
    
    /**
     * plottet die Punkte in ein 3D-Scatter-Plot und zeigt dieses an
     */
    public void plot()
    {
        ChartViewer viewer = new ChartViewer();
        
        // Einstellungen setzen
        ThreeDScatterChart c = new ThreeDScatterChart(1000, 1000);
        c.setPlotRegion(500, 480, 600, 600, 450);
        c.xAxis().setTitle("R", "Arial Bold", 10);
        c.yAxis().setTitle("G", "Arial Bold", 10);
        c.zAxis().setTitle("B", "Arial Bold", 10);
        c.xAxis().setDateScale(0, 255);
        c.yAxis().setDateScale(0, 255);
        c.zAxis().setDateScale(0, 255);
        c.setViewAngle(alpha, beta);
        
        // Bildpunkte
        double[] x = new double[image.size()];
        double[] y = new double[image.size()];
        double[] z = new double[image.size()];
        for (int i = 0; i < image.size(); i++) {
            x[i] = image.get(i).r;
            y[i] = image.get(i).g;
            z[i] = image.get(i).b;
        }
        //               Koordinaten    Form        Größe  Farbe ARGB  Rahmen ARGB
        c.addScatterGroup(x,y,z, "", Chart.CircleShape, 5, 0xE0FF0000, 0xFF000000);
        
        // Quantenpunkte
        x = new double[quants.size()];
        y = new double[quants.size()];
        z = new double[quants.size()];
        for (int i = 0; i < quants.size(); i++) {
            x[i] = quants.get(i).r;
            y[i] = quants.get(i).g;
            z[i] = quants.get(i).b;
        }
        c.addScatterGroup(x,y,z, "", Chart.CircleShape, 12);
        
        viewer.setChart(c);
        
        drawPanel.removeAll();
        drawPanel.add(viewer);
        
        frame.pack();
    }
    
    /**
     * Lies die vorhandenen JPG-Dateien aus dem Ordner inputs aus
     * 
     * @return String[] Dateinamen
     */
    private String[] getJPGs() {
        ArrayList<String> result = new ArrayList<String>();
        
        File d = new File("./inputs/");
        File[] list = d.listFiles();
        for(int i=0; i<list.length; i++) {
            String n = list[i].getName();
            // nur JPG-Bilder
            if (n.matches(".*\\.[jJ][pP][eE]?[gG]$")) {
                result.add(n);
            }
        }

        String[] ret = new String[result.size()];
        return result.toArray(ret);
    }
    
    /**
     * Button-Reaktivität
     * 
     * @param e ActionEvent
     */
    public void actionPerformed(ActionEvent e) {
        /**
         * Pfeilbuttons: Ändern der Ansicht
         */
        if (e.getSource() == this.vr) beta = (beta + 345) % 360;
        if (e.getSource() == this.vl) beta = (beta + 15) % 360;
        if (e.getSource() == this.vu) alpha = (alpha + 345) % 360;
        if (e.getSource() == this.vd) alpha = (alpha + 15) % 360;
        
        /**
         * Datei laden und RGB-Daten in ArrayList speichern
         */
        if (e.getSource() == this.b_load) {
            try {
                this.orig = Image.readFile("./inputs/" + (String)this.s_input.getSelectedItem());
                for (RGB p : this.orig) {
                    // kopiere die originalen Daten, damit die Liste später gemischt werden kann
                    this.image.add(p);
                }
            } catch (Exception ex) {}
        }
        /**
         * Zufällige Punkte erzeugen
         */
        if (e.getSource() == this.b_gen) {
            this.quants = new ArrayList<>();
            for (int i = 0; i < Integer.parseInt(this.t_anz.getText()); i++) {
                this.quants.add(new RGB(true));
            }
        }
        /**
         * Epoche durchlaufen
         */
        if (e.getSource() == this.b_epoc) Quant.doEpoch(this.image, this.quants);
        /**
         * Nicht bewegte Punkte versetzen
         */
        if (e.getSource() == this.b_reset) Quant.resetQuants(this.quants);
        /**
         * quantifiziertes Bild speichern
         */
        if (e.getSource() == this.b_save) {
            try {
                Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "./outputs/" + this.t_output.getText(), this.orig, this.quants);
            } catch (Exception ex) {}
        }

        // neue Anzeige rendern
        this.plot();
    }
}
