package de.wwwu.awolf.presenter.evaluation.measures;

import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.presenter.util.FastElementSelector;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

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


    private List<Double> percentageError;

    /**
     * Konstruktor
     *
     * @param lines Liste der Geraden
     * @param m     Steigung
     * @param b     y-Achenabschnitt
     */
    public PercentageErrorBasedMeasure(final Set<Line> lines, Double m, Double b) {

        //Berechnung des Sampson-Fehlers
        List<Line> linesAsList = new ArrayList<>(lines);
        List<Double> sampson = new ArrayList<>();
        for (Line line : linesAsList) {
            Double e = Math.pow(m * line.getM() - line.getB() + b, 2) / (Math.pow(m, 2) + 1);
            sampson.add(e);
        }

        percentageError = new ArrayList<>();
        //Berechnung der prozentuelen-Fehlers
        for (int j = 0; j < sampson.size(); j++) {
            percentageError.add(100 * sampson.get(j) / linesAsList.get(j).getB());
        }
    }

    /* Percentege Error Approximation Measures */
    //verschiedene Eingaben für einen Alg.

    /**
     * Mean Absolute Precentage Error
     *
     * @return Ergebnis
     */
    public Double mape() {
        double error = 0;

        for (Double d : percentageError) {
            error += Math.abs(d);
        }

        error /= percentageError.size();

        return error;
    }

    /**
     * Median Absolute Precentage Error:
     *
     * @return Ergebnis
     */
    public Double mdape() {

        ArrayList<Double> abs = new ArrayList<>();

        for (Double d : percentageError) {
            abs.add(Math.abs(d));
        }

        return FastElementSelector.randomizedSelect(abs, abs.size() * 0.5);
    }

    /**
     * Root Mean Square Percentage Error
     *
     * @return Ergebnis
     */
    public Double rmspe() {
        double error = 0;

        for (Double d : percentageError) {
            error += Math.pow(d, 2);
        }

        error /= percentageError.size();

        return Math.sqrt(error);
    }

    /**
     * Root Median Square Percentage Error
     *
     * @return Ergebnis
     */
    public Double rmdspe() {
        List<Double> squares = new ArrayList<>();
        for (Double d : percentageError) {
            squares.add(Math.pow(d, 2));
        }

        return Math.sqrt(FastElementSelector.randomizedSelect(squares, squares.size() * 0.5));
    }
}
