package de.wwwu.awolf.presenter;

import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.communication.AlgorithmData;
import de.wwwu.awolf.model.communication.Data;
import de.wwwu.awolf.model.communication.EvaluationData;
import de.wwwu.awolf.presenter.data.DataHandler;
import de.wwwu.awolf.presenter.evaluation.EvaluatationHandler;
import de.wwwu.awolf.presenter.util.Logging;

import javax.swing.*;
import java.io.File;
import java.util.Set;


/**
 * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
 *
 * @Author: Armin Wolf
 * @Email: a_wolf28@uni-muenster.de
 * @Date: 28.05.2017.
 */
public class Presenter extends AbstractPresenter {

    private static Presenter instance;

    private Presenter() {
        super();
    }

    public static Presenter getInstance() {
        if (instance == null) {
            instance = new Presenter();
        }

        return instance;
    }

    @Override
    protected void visualizeTsAlgorithm(Data data) {
        AlgorithmData algorithmData = (AlgorithmData) data;
        SwingUtilities.invokeLater(() -> getView().visualizeTS(algorithmData.getLineData()));
        Logging.logInfo("Theil-Sen Estimator");
        Logging.logInfo(algorithmData.getLineData().toString());
    }

    @Override
    protected void visualizeRmAlgorithm(Data data) {
        AlgorithmData algorithmData = (AlgorithmData) data;
        SwingUtilities.invokeLater(() -> getView().visualizeRM(algorithmData.getLineData()));
        Logging.logInfo("Repeated Median Estimator");
        Logging.logInfo(algorithmData.getLineData().toString());
    }

    @Override
    protected void visualizeLmsAlgorithm(Data data) {
        AlgorithmData algorithmData = (AlgorithmData) data;
        SwingUtilities.invokeLater(() -> getView().visualizeLMS(algorithmData.getLineData()));
        Logging.logInfo("Least Median of Squares");
        Logging.logInfo(algorithmData.getLineData().toString());
    }

    @Override
    protected void evaluatedDatas(Data data) {
        EvaluationData evaluationData = (EvaluationData) data;
        SwingUtilities.invokeLater(() -> getView().appendEvalResults(evaluationData.getMultipleColumnResult()));
    }

    /***************************************************************************************************************************
     *                                          Hilfsmethoden
     ***************************************************************************************************************************/


    /**
     * Startet den Export des akteullen Datensatzes (nur der Geraden)
     *
     * @param file Datei in der die Informationen gespeichert werden sollen
     */
    public void exportDataset(File file) {
        getDataHandler().exportData(file, getModel().getLines());
    }

    /**
     * Startet den Export des akteullen Datensatzes im Rahmen der Evaluation (nur der Geraden)
     *
     * @param file Datei in der die Informationen gespeichert werden sollen
     */
    public void exportEvaluationDataset(File file) {
        getDataHandler().exportData(file, getEvaluatationHandler().getData());
        Logging.logInfo("Export was successful");
    }

    /**
     * Startet den Import des Datensatzes.
     *
     * @param file importierender Datensatz
     */
    public Set<Line> importDataset(File file) {
        Set<Line> data = getDataHandler().getData(file);
        getModel().setLines(data);
        //Berechnung der Schnittpunkte und vis. der Ergebnisse (anz. Geraden, anz. Schnittpunkte)
        Logging.logInfo("Import was successful! ");
        return data;
    }

    /**
     * Startet das generieren der Datensätze der Größe <code>n</code>
     *
     * @param n    Größe des Datensatzes
     * @param type Art der Datensatzes
     */
    public Set<Line> generateDataset(int n, DataHandler.DataType type) {
        Set<Line> data = getDataHandler().getData(type, n);
        getModel().setLines(data);
        Logging.logInfo("Generate was successful!");
        return data;
    }

    /**
     * Startet die Evaluation zu einen gegegbenen Typ mit den Informationen zu den Datensatz.
     * Beispielsweise kann ein Alg. auf mit verschiedenen Datensätzen untersucht werden, oder mehrere Algorithmen
     * auf einem gegebenen Datensatz.
     *
     * @param typ        Typ der Evaluation
     * @param n          Größe des Datensatzes
     * @param alg        code für die auszuführenden Algorithmen (siehe <code>EvaluationPanel.checkSelection()</code> Method)
     * @param datasetTyp Typ des Datensatzes (Geradem Punktwolke, Kreis und Gerade)
     */
    public void startEvaluation(int typ, int n, int alg, DataHandler.DataType datasetTyp) {
        getExecutor().submit(new EvaluatationHandler(typ, n, alg, datasetTyp));
    }

    /**
     * Startet die Evaluation zu einen gegegbenen Datensatz, der importiert wird.
     * Beispielsweise kann ein Alg. auf mit verschiedenen Datensätzen untersucht werden, oder mehrere Algorithmen
     * auf einem gegebenen Datensatz.
     *
     * @param typ  Typ der Evaluation
     * @param alg  code für die auszuführenden Algorithmen (siehe <code>EvaluationPanel.checkSelection()</code> Method)
     * @param file Typ des Datensatzes (Geradem Punktwolke, Kreis und Gerade)
     */
    public void startEvaluation(int typ, int alg, File file) {
        getExecutor().submit(new EvaluatationHandler(typ, alg, file));
    }
}
