package presenter.generator;

import model.Line;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Random;

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

    private Double m;
    private Double b;
    private Random random;

    public DatasetGenerator(Double m, Double b) {
        this.m = m;
        this.b = b;
        random = new Random();
        random.setSeed(9999);
    }

    public DatasetGenerator() {
        random = new Random();
    }


    public LinkedList<Line> generateDataCloud(int size) {
        LinkedList<Line> lines = new LinkedList<>();
        m = 1 + random.nextDouble();
        b = random.nextDouble();


        for (int i = 1; i < (size + 1); i++) {
            double y = (random.nextGaussian() * 100) % 100;
            double signal = m * i + b;
            signal *= -1;

            Line line = new Line((double) i, signal - y);
            line.setId(i - 1 + "");
            lines.add(line);
        }
        String[] ret = {"generator", "Es wurden " + 100 + " Daten generiert mit den Parametern",
                "</br> <b>m</b> = " + m + "",
                "</br> <b>b</b> = " + b + ""};
        setChanged();
        notifyObservers(ret);
        return lines;
    }

    public LinkedList<Line> generateDataLines(int size) {
        LinkedList<Line> lines = new LinkedList<>();
        return generateDataLines(lines, size);
    }

    private LinkedList<Line> generateDataLines(LinkedList<Line> lines, int n) {
        m = 5d;
        b = 0d;


        int size = 0;
        HashMap<Double, Double> points = new HashMap<>();

        //speichere die Koordinaten in einer HashMap, damit keine Punkte
        //entstehen deren x-Koordinate zu sehr beieinander liegt.
        while (size < n) {
            double y = random.nextGaussian();
            double signal = m * y + b;
            signal *= -1;

            if (!points.containsKey(y)) {
                points.put(y, signal);
                size++;
            }
        }

        int idx = lines.size();
        for (Double d : points.keySet()) {
            Line line = new Line((double) d, points.get(d));
            line.setId(idx + "");
            lines.add(line);
            idx++;
        }

        String[] ret = {"generator", "Es wurden " + 100 + " Daten generiert mit den Parametern"};
        setChanged();
        notifyObservers(ret);
        return lines;
    }


    public LinkedList<Line> generateCircle(int size) {
        LinkedList<Line> lines = new LinkedList<>();

        double from = 0;
        double to = Math.PI * 5;
        //obere Grenze für die neuen Punkte
        int n = size / 2 + lines.size();

        //calculate the distance between every two points
        double distance = (to - from) / ((double) n);

        //create points
        double currentDistance = from;
        //an die aktuelle Liste dranhängen
        for (int i = lines.size(); i < n; i++) {
            double x = Math.cos(currentDistance);
            double y = Math.sin(currentDistance);


            Line line = new Line(x, y);
            line.setId(i + "");
            lines.add(line);

            //distance for the next iteration
            currentDistance += distance;
        }


        return generateDataLines(lines, size / 2);
    }

}

