package presenter.algorithms.naiv;

import model.Line;
import model.Point;
import presenter.algorithms.Algorithm;
import presenter.algorithms.util.FastElementSelector;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;

/**
 * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
 *
 * @Author: Armin Wolf
 * @Email: a_wolf28@uni-muenster.de
 * @Date: 15.09.2017.
 */
public class NaivLeastMedianOfSquaresEstimator implements Algorithm {
    private ArrayList<Point> set = new ArrayList<>();

    private Integer n;
    private Double ds, b, m;

    public NaivLeastMedianOfSquaresEstimator(LinkedList<Line> lines) {
        for (Line l :lines){
            set.add(new Point(l.getM(),l.getB()));
        }
    }


    private void crudeAlg(){
        ds = Double.MAX_VALUE;
        b = 0d;
        m = 0d;
        ArrayList<Point> triple = new ArrayList<>();
        Double beta;
        Double alpha;
        Double dijk;
        for (Point i : set){
            for (Point j : set) {
                for (Point k : set){
                    triple.add(i);
                    triple.add(j);
                    triple.add(k);
                    Collections.sort(triple);
                    beta    = (triple.get(0).getY() - triple.get(2).getY()) / (triple.get(0).getX() - triple.get(2).getX());
                    alpha   = (triple.get(1).getY() + triple.get(2).getY() - ( beta * (triple.get(1).getX() + triple.get(2).getX()))) / 2f;
                    dijk    = f(alpha, beta);
                    if (dijk < ds){
                        ds = dijk;
                        b = alpha;
                        m = beta;
                       // System.out.printf("Distanz: %6.2f\tAlpha: %6.2f\tBeta: %6.2f",ds,b,m);
                    }
                    triple.clear();
                }
            }
        }
        System.out.printf("Naiv LMS: %6.2f * x + %6.3f\n", m, b);
    }



    private Double f(Double a, Double b){
        ArrayList<Double> res = new ArrayList<>();
        for (Point p : set){
            res.add(Math.abs(p.getY() - (a + b * p.getX())));
        }
        return FastElementSelector.randomizedSelect(res, res.size()/2);
    }

    @Override
    public void run() {
        crudeAlg();
    }

    @Override
    public void getResult() {

    }

    public Double getB() {
        return b * -1;
    }

    public Double getM() {
        return m * -1;
    }
}
