package view.panels;

import model.Line;
import presenter.Presenter;
import view.MainFrame;
import view.custom.ButtonGroupAtLeastTwo;
import view.custom.ColorColumnRenderer;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

/**
 * Created by
 * Armin Wolf
 * on 02.08.17.
 */
public class EvaluationPanel extends JPanel {

    private final MainFrame view;
    private JTable table;
    private JTableHeader header;
    private JButton start;
    private JButton latexExport;
    private JButton clearTable;
    private JButton exportData;
    private JRadioButton evalTypeOne; //1: Alg - N: Data
    private JRadioButton evalTypeTwo; //N: Alg - 1: Data
    private ButtonGroup radiobuttonGroup;
    private ButtonGroup checkboxGroup;
    private ButtonGroupAtLeastTwo checkboxAtLeastOne;

    private JCheckBox lms; //1: Alg - N: Data
    private JCheckBox rm; //N: Alg - 1: Data
    private JCheckBox ts; //1: Alg - N: Data

    private JPanel comp;
    private JPanel algorithmPanel;
    private JPanel leftSidePanel;
    private JPanel datasetCount;
    private JComboBox<Integer> datasetCountChoice;
    private JComboBox<String> datasetType;
    private JLabel datasetCountLabel;

    private JSplitPane splitPane;

    private DefaultTableModel model;
    private int currentRowOfTypes;
    private JPanel buttonPanel;
    private PlotPanel plotPanel;
    private String[] selections = {"Approximationsgüte", "Least Median of Squares", "Repeated-Median", "Theil-Sen"};

    public EvaluationPanel(MainFrame view) {
        super();
        this.view = view;
        this.setLayout(new BorderLayout());
        this.currentRowOfTypes = 0;

        init();
        addListener();
        addComponents();

    }

    private void init() {
        datasetCountLabel = new JLabel("Größe des Datensatzes");
        Integer[] choice = {50, 100, 200, 500, 1000, 1500};
        datasetCountChoice = new JComboBox(choice);
        String[] datatypes = {"Punktwolke", "Gerade", "Kreis und Gerade"};
        datasetType = new JComboBox<>(datatypes);

        start = new JButton("Start");
        latexExport = new JButton("LaTex Export");
        clearTable = new JButton("Löschen");
        exportData = new JButton("Datenexport");
        latexExport.setEnabled(false);
        clearTable.setEnabled(false);
        exportData.setEnabled(false);
        evalTypeOne = new JRadioButton("Algorithmus evaluieren");
        evalTypeTwo = new JRadioButton("Algorithmen vergleichen");
        lms = new JCheckBox("Least Median of Squares");
        rm = new JCheckBox("Repeated Median");
        ts = new JCheckBox("Theil-Sen");
        radiobuttonGroup = new ButtonGroup();
        checkboxGroup = new ButtonGroup();
        checkboxAtLeastOne = new ButtonGroupAtLeastTwo();
        buttonPanel = new JPanel(new FlowLayout());
        leftSidePanel = new JPanel(new BorderLayout());
        comp = new JPanel(new GridLayout(0, 1));
        plotPanel = new PlotPanel();
        model = new DefaultTableModel() {
            @Override
            public boolean isCellEditable(int row, int column) {
                //all cells false
                return false;
            }
        };
        table = new JTable(model);
        UIManager.put("TableHeader.font", new Font("SansSerif", Font.BOLD, 14));
        UIManager.put("TableHeader.foreground", Color.WHITE);
        header = table.getTableHeader();
        header.setBackground(Color.GRAY);

        splitPane = new JSplitPane();
        algorithmPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        datasetCount = new JPanel(new FlowLayout(FlowLayout.LEFT));

    }

    private void addComponents() {
        evalTypeOne.setSelected(true);
        lms.setSelected(true);
        checkboxGroup.add(lms);
        checkboxGroup.add(rm);
        checkboxGroup.add(ts);

        radiobuttonGroup.add(evalTypeOne);
        radiobuttonGroup.add(evalTypeTwo);

        buttonPanel.add(start);
        buttonPanel.add(clearTable);
        buttonPanel.add(exportData);
        buttonPanel.add(latexExport);

        algorithmPanel.add(lms);
        algorithmPanel.add(rm);
        algorithmPanel.add(ts);

        datasetCount.add(datasetCountLabel);
        datasetCount.add(datasetCountChoice);
        datasetCount.add(datasetType);

        comp.add(evalTypeOne);
        comp.add(evalTypeTwo);
        comp.add(algorithmPanel);
        comp.add(datasetCount);


        comp.setBorder(new TitledBorder("Konfiguration"));


        //Tabelle
        model.setColumnIdentifiers(selections);
        table.setDragEnabled(true);
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setWheelScrollingEnabled(true);
        scrollPane.setBorder(new TitledBorder("Ergebnisse"));


        //Plot
        plotPanel.createPlot(new LinkedList<>());
        plotPanel.setBorder(new TitledBorder("Plot"));

        leftSidePanel.add(comp, BorderLayout.NORTH);
        leftSidePanel.add(scrollPane, BorderLayout.CENTER);

        //Splitpane
        splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
        splitPane.setResizeWeight(.5d);
        splitPane.setContinuousLayout(true);
        splitPane.setLeftComponent(leftSidePanel);
        splitPane.setRightComponent(plotPanel);

        this.add(splitPane, BorderLayout.CENTER);

        this.add(buttonPanel, BorderLayout.SOUTH);

        TableColumn tm = table.getColumnModel().getColumn(0);
        tm.setCellRenderer(new ColorColumnRenderer(Color.lightGray, Color.blue));
    }

    private void addListener() {
        start.addActionListener(e -> {
            int type;
            int alg;
            int n;
            if (radiobuttonGroup.isSelected(evalTypeOne.getModel())) {
                type = 0;
            } else {
                type = 1;
            }
            alg = checkSelection();
            n = (Integer) datasetCountChoice.getSelectedItem();
            String datatyp = (String) datasetType.getSelectedItem();
            ((Presenter) view.getPresenter()).startEvaluation(type, n, alg, datatyp);
            clearTable.setEnabled(true);
            latexExport.setEnabled(true);
            exportData.setEnabled(true);
        });

        evalTypeOne.addActionListener(e -> {
            checkboxAtLeastOne.remove(lms);
            checkboxAtLeastOne.remove(rm);
            checkboxAtLeastOne.remove(ts);
            lms.setSelected(true);

            checkboxGroup.add(lms);
            checkboxGroup.add(rm);
            checkboxGroup.add(ts);
        });

        evalTypeTwo.addActionListener(e -> {
            checkboxGroup.remove(lms);
            checkboxGroup.remove(rm);
            checkboxGroup.remove(ts);

            checkboxAtLeastOne.addAll(lms, rm, ts);

            lms.setSelected(true);
            rm.setSelected(true);
        });

        latexExport.addActionListener(e -> {
            SwingUtilities.invokeLater(() -> {
                File file = null;
                JFileChooser chooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
                chooser.setPreferredSize(new Dimension(800, 700));
                chooser.setFileFilter(new FileNameExtensionFilter("LaTeX-Datei", "tex", "text"));

                chooser.setMultiSelectionEnabled(false);
                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

                if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
                    //System.out.println ("Datei "+chooser.getSelectedFile()+ " ausgewählt.");
                    file = chooser.getSelectedFile();
                    String filename = file.getAbsolutePath().contains(".tex") ? file.getAbsolutePath() : file.getAbsolutePath().concat(".tex");
                    File withExtension = new File(filename);
                    final File input = withExtension;
                    ((Presenter) view.getPresenter()).startResultExport(model, input);
                }
            });
        });

        clearTable.addActionListener(e -> {
            SwingUtilities.invokeLater(() -> {
                int n = model.getDataVector().size();
                for (int i = 0; i < n; i++) {
                    model.removeRow(0);
                    currentRowOfTypes--;
                }
                this.revalidate();
                latexExport.setEnabled(false);
                clearTable.setEnabled(false);
                exportData.setEnabled(false);
            });
        });


        exportData.addActionListener(e -> {
            SwingUtilities.invokeLater(() -> {
                JOptionPane.showMessageDialog(this, "Boooooooooooooooooooooooooooooooooooooooooooooooooooooo! :)");
            });
        });


    }

    public void addColumn(Object[] data, int col, boolean b) {
        if (b) {
            addBlankRows(data.length);
        }
        for (int i = 0; i < data.length; i++) {
            int row = currentRowOfTypes - data.length + i;
            model.setValueAt(data[i], row, col);
        }
        this.repaint();
        this.revalidate();
    }

    public void addRow(Object[] data) {
        addBlankRows(1);
        for (int i = 0; i < 4; i++) {
            model.setValueAt(data[i], currentRowOfTypes, i);
        }

        currentRowOfTypes++;
        this.repaint();
        this.revalidate();
    }

    public void drawLines(ArrayList<Double[]> alg) {
        Paint[] color = {Color.ORANGE, Color.RED, Color.MAGENTA};
        String[] name = {"LMS", "RM", "TS"};

        for (Double[] o : alg) {
            int i = o[0].intValue();
            Double m = o[1];
            Double b = o[2];
            plotPanel.addLineToPlot(m, b, color[i], name[i]);
        }
    }

    public void drawLines(Object[] results, int alg) {
        String[] castedResults = Arrays.copyOf(results, results.length, String[].class);
        Paint[] color = {Color.ORANGE, Color.RED, Color.MAGENTA};
        String[] name = {"LMS", "RM", "TS"};
        String[] nName = {"Brute-force LMS", "Brute-force RM", "Brute-force TS"};

        Double m = Double.parseDouble(castedResults[0]);
        Double b = Double.parseDouble(castedResults[1]);
        plotPanel.addLineToPlot(m, b, color[alg], name[alg]);

        Double nM = Double.parseDouble(castedResults[2]);
        Double nB = Double.parseDouble(castedResults[3]);
        plotPanel.addLineToPlot(nM, nB, Color.BLACK, nName[alg]);
    }

    public void setDualPoints(LinkedList<Line> points) {
        plotPanel = new PlotPanel();
        plotPanel.setBorder(new TitledBorder("Plot"));
        splitPane.setRightComponent(plotPanel);
        plotPanel.createPlot(points);
        plotPanel.repaint();
        plotPanel.revalidate();
    }

    private void addBlankRows(int n) {
        for (int i = 0; i < n; i++) {
            String[] tmp = {"", "", "", "",};
            model.addRow(tmp);
        }
    }

    public void setCurrentRow(int val) {
        this.currentRowOfTypes += val;
    }


    private int checkSelection() {
        if (lms.isSelected() && rm.isSelected() && ts.isSelected()) {
            return 6;
        } else if (!lms.isSelected() && rm.isSelected() && ts.isSelected()) {
            return 5;
        } else if (lms.isSelected() && !rm.isSelected() && ts.isSelected()) {
            return 4;
        } else if (lms.isSelected() && rm.isSelected() && !ts.isSelected()) {
            return 3;
        } else if (!lms.isSelected() && !rm.isSelected() && ts.isSelected()) {
            return 2;
        } else if (!lms.isSelected() && rm.isSelected() && !ts.isSelected()) {
            return 1;
        } else if (lms.isSelected() && !rm.isSelected() && !ts.isSelected()) {
            return 0;
        } else {
            throw new IllegalStateException("Mindestens ein Algortihmus muss selektiert werden");
        }
    }
}
