
package de.ivu.elect.business.sitzberechnung.control.dhondtweiterverteilung;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nullable;

import de.ivu.elect.business.sitzberechnung.control.dhondt.DHondtTeilnehmerErgebnis;
import de.ivu.elect.business.sitzberechnung.control.dhondt.DHondtVerteilung;
import de.ivu.elect.business.sitzberechnung.control.util.Fraction;
import de.ivu.elect.business.sitzberechnung.control.verteilung.AbstractVerteilungsErgebnis;
import de.ivu.elect.business.sitzberechnung.control.verteilung.Teilnehmer;

/**
 * Das Ergebnis einer Sitzverteilung nach D'Hondt. Sie wird als Quasi-Quotenverfahren
 * (http://www.wahlrecht.de/verfahren/quotenverfahren.html) umgesetzt. D.h. zunächst wird die Stimmenzahl durch den
 * Hare-Quotienten dividiert und auf die nächste ganze Zahl abgerundet. Anschließend werden Restsitze vergeben. Man
 * erhält es nach Verteilung der abgerundeten Sitze und der Restsitze von einer {@link DHondtVerteilung}. Durch eine
 * evtl. spätere Verteilung nach Los (oder anderen Kriterien) werden nachträglich noch Sitze vergeben und damit dieses
 * Objekt modifiziert. Es enthält für jeden Teilnehmer an der Verteilung ein {@link DHondtTeilnehmerErgebnis}, das
 * ebenfalls noch durch spätere Verteilung nach Los (oder anderen Kriterien) modifiziert werden kann.
 * 
 *
 */
public class DHondtWeiterverteilungErgebnis
    extends
      AbstractVerteilungsErgebnis<DHondtWeiterverteilungTeilnehmerErgebnis> {

  /**
   * @return Ergebnis der Verteilung, wenn keine richtige Verteilung stattgefunden hat
   */
  public static DHondtWeiterverteilungErgebnis ohneVerteilung(long anzahlSitze,
      List< ? extends Teilnehmer> dieTeilnehmer) {
    List<DHondtWeiterverteilungTeilnehmerErgebnis> teilnehmerErgebnisse = new ArrayList<>();
    for (Teilnehmer teilnehmer : dieTeilnehmer) {
      teilnehmerErgebnisse.add(DHondtWeiterverteilungTeilnehmerErgebnis.ohneVerteilung(teilnehmer));
    }

    return new DHondtWeiterverteilungErgebnis(anzahlSitze, teilnehmerErgebnisse);
  }

  /**
   * Ergebnis der DHondtVerteilung ohne dass ein Losverfahren nötig war
   */
  public DHondtWeiterverteilungErgebnis(long anzahlSitze,
      List<DHondtWeiterverteilungTeilnehmerErgebnis> teilnehmerErgebnisse) {
    this(anzahlSitze, teilnehmerErgebnisse, Collections.<DHondtWeiterverteilungTeilnehmerErgebnis> emptyList(), 0);
  }

  public DHondtWeiterverteilungErgebnis(long anzahlSitze,
      List<DHondtWeiterverteilungTeilnehmerErgebnis> teilnehmerErgebnisse,
      List<DHondtWeiterverteilungTeilnehmerErgebnis> teilnehmerAmLosverfahren, long anzahlSitzeZuVerlosen) {
    super(anzahlSitze, teilnehmerErgebnisse, teilnehmerAmLosverfahren, anzahlSitzeZuVerlosen);
  }

  /**
   * @return den Quotienten, mit dem der nächste Sitz zugeteilt worden wäre
   */
  public Fraction getNaechsterQuotient() {
    Fraction max = Fraction.ZERO;
    for (DHondtWeiterverteilungTeilnehmerErgebnis teilnehmerErgebnis : getTeilnehmerErgebnisse()) {
      if (max.compareTo(teilnehmerErgebnis.getNaechsterQuotient()) < 0) {
        max = teilnehmerErgebnis.getNaechsterQuotient();
      }
    }

    return max;
  }

  /**
   * @return den Quotienten, mit dem der letzte Sitz zugeteilt wurde. null, wenn kein Sitz zugeteilt wurde.
   */
  public @Nullable Fraction getLetzterQuotient() {
    Fraction min = null;
    for (DHondtWeiterverteilungTeilnehmerErgebnis teilnehmerErgebnis : getTeilnehmerErgebnisse()) {
      if (teilnehmerErgebnis.getSitze() > 0) {
        Fraction quotient = Fraction.getFraction(teilnehmerErgebnis.getTeilnehmer().getStimmen(),
            teilnehmerErgebnis.getSitzeGesamt());
        if (min == null || min.compareTo(quotient) > 0) {
          min = quotient;
        }
      }
    }

    return min;
  }

}
