package presenter;

import model.Interval;
import model.LineModel;
import presenter.algorithms.util.IntersectionComputer;
import presenter.algorithms.util.IntersectionCounter;
import presenter.evaluation.EvaluateAlgorithms;
import view.MainFrame;

import javax.swing.*;
import java.util.Observable;
import java.util.Observer;

/**
 * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
 *
 * @Author: Armin Wolf
 * @Email: a_wolf28@uni-muenster.de
 * @Date: 10.09.2017.
 */
public abstract class AbstractPresenter implements Observer {

    private LineModel model;
    private MainFrame view;

    private EvaluateAlgorithms eval;


    public AbstractPresenter(LineModel model, MainFrame view) {
        this.model = model;
        this.view = view;
    }

    @Override
    public void update(Observable o, Object arg) {
        String[] result = ((String[]) arg);

        if (result[0] == "eval-dataset-generated") {
            SwingUtilities.invokeLater(() -> getView().addEvalDataset(getEval().getData()));
        }

        if (result[0] == "eval-d") {
            SwingUtilities.invokeLater(() -> getView().appendEvalResult(result, Integer.parseInt(result[1]), false));
        }

        if (result[0] == "eval-ds") {
            SwingUtilities.invokeLater(() -> getView().appendEvalResult(result));
        }

        if (result[0] == "eval-t") {
            SwingUtilities.invokeLater(() -> getView().appendEvalResult(result, Integer.parseInt(result[1]), true));
        }

        if (result[0] == "lines-res") {
            SwingUtilities.invokeLater(() -> getView().drawLineResult(result, Integer.parseInt(result[1])));
        }

        if (result[0] == "lines-res-mult") {
            SwingUtilities.invokeLater(() -> getView().drawLineResults(result));
        }

        if (result[0] == "lms") {
            SwingUtilities.invokeLater(() -> {
                getView().visualizeLMS(Double.parseDouble(result[1]), Double.parseDouble(result[2]));
                //getView().setLmsIsComplete(true);
                getView().logHeading("Least Median of Squares");
                getView().log("<b>m:</b> " + result[1]);
                getView().log("<b>b:</b> " + result[2]);
                getView().logSuccess("Berechnung wurde Erfolgreich durchgeführt <hr>");
            });
        }

        if (result[0] == "rm") {
            SwingUtilities.invokeLater(() -> {
                getView().visualizeRM(Double.parseDouble(result[1]), Double.parseDouble(result[2]));
                getView().logHeading("Repeated Median Estimator");
                getView().log("<b>m:</b> " + result[1]);
                getView().log("<b>b:</b> " + result[2]);
                getView().logSuccess("Berechnung wurde Erfolgreich durchgeführt <hr>");
            });
        }

        if (result[0] == "ts") {
            SwingUtilities.invokeLater(() -> {
                getView().visualizeTS(Double.parseDouble(result[1]), Double.parseDouble(result[2]));
                getView().logHeading("Theil-Sen Estimator");
                getView().log("<b>m:</b> " + result[1]);
                getView().log("<b>b:</b> " + result[2]);
                getView().logSuccess("Berechnung wurde Erfolgreich durchgeführt <hr>");
            });
        }

        if (result[0] == "import") {
            Double max = Double.parseDouble(result[1]);
            Double current = Double.parseDouble(result[2]);
            Integer progress = (int) (100 * (current / max));
            //100% erreicht
            if (progress == 100) {
                Thread t = new Thread(() -> {
                    calculateIntersections();
                });
                t.start();
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                SwingUtilities.invokeLater(() -> {
                    getView().showImportProgress(progress);
                    getView().enableFunctionality();
                    getView().getProgressDialog().dispose();
                    getView().logHeading("Import aus Datei");
                    getView().log("Anzahl der Geraden: "+ getModel().getLines().size() + ".");
                    getView().log("Anzahl der Schnittpunkte: "+getModel().getNodes().size()+".");
                    getView().logSuccess("Import war Erfolgreich! <hr>");
                });
            } else {
                SwingUtilities.invokeLater(() -> {
                    getView().showImportProgress(progress);
                });
            }
        }
        if (result[0] == "export") {
            SwingUtilities.invokeLater(() -> {
                getView().logHeading("Export der Daten als CSV");
                getView().logSuccess("Export war Erfolgreich");
                getView().log(result[1] + "<hr>");
            });
        }

        if (result[0] == "generator") {
            SwingUtilities.invokeLater(() -> {
                getView().logSuccess("Generierung war Erfolgreich");
                getView().log(result[1] + "<hr>");
            });
        }

        if (result[0] == "import-picture") {
            //100% erreicht
            SwingUtilities.invokeLater(() -> {
                getView().enableFunctionality();
                getView().logHeading("Import eines Bildes");
                getView().log("Anzahl der Geraden: "+ getModel().getLines().size() + ".");
                getView().log("Anzahl der Schnittpunkte: "+getModel().getNodes().size()+".");
                getView().logSuccess("Der Import war Erfolgreich! <hr>");
            });

            Thread t = new Thread(() -> {
                calculateIntersections();
            });
            t.start();
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }




    public void calculateIntersections() {
        try {
            Thread thread = new Thread(() -> {
                getModel().resetRanges();
                IntersectionComputer intersectionComputer = new IntersectionComputer(getModel().getLines());
                getModel().setNodes(intersectionComputer.compute());

                getModel().setxMaximum(intersectionComputer.getxMaximum());
                getModel().setxMinimum(intersectionComputer.getxMinimum());
                getModel().setyMaximum(intersectionComputer.getyMaximum());
                getModel().setyMinimum(intersectionComputer.getyMinimum());
            });
            thread.start();
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public LineModel getModel() {
        return model;
    }

    public void setModel(LineModel model) {
        this.model = model;
    }

    public MainFrame getView() {
        return view;
    }

    public void setView(MainFrame view) {
        this.view = view;
    }

    public EvaluateAlgorithms getEval() {
        return eval;
    }

    public void setEval(EvaluateAlgorithms eval) {
        this.eval = eval;
    }
}
