package edu.whs.spin2018.baoapp.views.spiel;

import android.util.Log;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * Modelliert die klickbare Mulde auf dem Bildschirm.
 */
public class MuldenView {

    /**
     * Mittelpunkt der Mulde.
     */
    private final PositionAufBildschirm mitte;

    /**
     * Radius der Mulde.
     */
    private final float radius;

    /**
     * Views der Steine, die sich in der Mulde befinden
     */
    private ArrayList<SteinView> steine;

    private LinkedList<PositionAufBildschirm> freiePositionen;
    private LinkedList<PositionAufBildschirm> belegtePositionen;

    /**
     * Erzeugt ein Objekt der Klasse MuldenView mit deren Koordianten auf dem Bildschirm und dem
     * Radius der MuldenView
     *
     * @param position - Koordinaten auf dem Bildschirm
     * @param radius   - Radius der Mulde
     */
    public MuldenView(PositionAufBildschirm position, float radius) {
        this.steine = new ArrayList<>();
        this.radius = radius;
        this.mitte = new PositionAufBildschirm(position.getX() + radius, position.getY() + radius);


        freiePositionen = new LinkedList<>();
        freiePositionen.add(new PositionAufBildschirm(0.303f, 0.167f));
        freiePositionen.add(new PositionAufBildschirm(0.637f, 0.167f));
        freiePositionen.add(new PositionAufBildschirm(0.137f, 0.46f));
        freiePositionen.add(new PositionAufBildschirm(0.47f, 0.46f));
        freiePositionen.add(new PositionAufBildschirm(0.803f, 0.46f));
        freiePositionen.add(new PositionAufBildschirm(0.303f, 0.743f));
        freiePositionen.add(new PositionAufBildschirm(0.637f, 0.743f));
        belegtePositionen = new LinkedList<>();
    }

    public PositionAufBildschirm getCentoid() {
        double x0,x1,y0,y1,a;
        double signedArea = 0.0;
        double centX = 0.0;
        double centY = 0.0;
        for (int i = 0; i < steine.size()-1; i++) {
            x0 = steine.get(i).gibPositionAufBildschirm().getX();
            y0 = steine.get(i).gibPositionAufBildschirm().getY();
            x1 = steine.get(i+1).gibPositionAufBildschirm().getX();
            y1 = steine.get(i+1).gibPositionAufBildschirm().getY();
            a = x0 * y1 - x1 * y0;
            signedArea += a;
            centX += (x0 + x1) * a;
            centY += (y0 + y1) * a;
        }
        signedArea *= 0.5;
        centX /= 6.0 * signedArea;
        centY /= 6.0 * signedArea;
        return new PositionAufBildschirm((float)centX, (float)centY);
    }
    /**
     * Liefert eine zufaellige Position innerhalb eines Kreises mit dem uebergebenem radius
     *
     * @return zufaellige Position innerhalb eines Kreises
     */
    public PositionAufBildschirm gibZufaelligePositionInMulde(float offset) {

        PositionAufBildschirm posInMulde;
        /*
         * Das die Steine in den Mulden eher rechts liegen, liegt daran, dass der Ursprung der Steine
         * oben links in der Ecke liegt. Wenn dann der Ursprung des Steines auf einen Punkt
         * des Radiusses gelegt wird, wird der Stein weiter rechts von diesem Punkt angezeigt
         */
        if (freiePositionen.isEmpty()) {

            //Steine werden zufaellig gelegt
            double r = (radius - offset) * Math.sqrt(Math.random());

            double angle = Math.random() * Math.PI * 2;

            double x = Math.cos(angle) * r + mitte.getX();
            double y = Math.sin(angle) * r + mitte.getY();
            posInMulde = new PositionAufBildschirm((float) x, (float) y);
            posInMulde = getCentoid();
        } else {
            //Steine werden zufaellig auf vorberechnete Positionen gelegt
            Random ra = new Random();
            int zufallsIndex = ra.nextInt(freiePositionen.size());
            PositionAufBildschirm pos = freiePositionen.get(zufallsIndex);
            belegtePositionen.add(pos);
            freiePositionen.remove(zufallsIndex);
            posInMulde = new PositionAufBildschirm(
                    mitte.getX() + (pos.getX() - 0.5f) * 3f * offset * 1.5f,
                    mitte.getY() + (pos.getY() - 0.5f) * 3f * offset * 1.57f);
        }
        return posInMulde;
    }

    /**
     * Liefert alle Steine, die sich in der Mulde befinden.
     *
     * @return Liefert eine Liste von SteinViews zurück.
     */
    public ArrayList<SteinView> gibSteine() {
        return steine;
    }

    /**
     * Liefert die Anzahl an Steinen, die sich in der MuldenView befinden
     *
     * @return Anzahl der Steine in der MuldenView
     */
    public int gibAnzahlSteine() {
        return steine.size();
    }

    /**
     * Entfernt alle Steine aus der Mulde
     */
    public void entferneSteine() {
        freiePositionen.addAll(belegtePositionen);
        belegtePositionen.clear();
        this.steine.clear();
    }

    /**
     * Fuegt der Mulde einen Stein hinzu.
     *
     * @param stein - Stein der der Mulde hinzugefuegt werden soll
     */
    public void fuegeSteinHinzu(SteinView stein) {
        this.steine.add(stein);
    }

    /**
     * Fuegt der Mulde mehrere Steine hinzu.
     *
     * @param steine - Steine, die der Mulde hinzugefuegt werden sollen
     */
    public void fuegeSteineHinzu(List<SteinView> steine) {
        this.steine.addAll(steine);
    }
}
