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

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import javax.annotation.Nullable;

import de.ivu.elect.business.sitzberechnung.control.util.Fraction;
import de.ivu.elect.business.sitzberechnung.control.verteilung.Teilnehmer;
import de.ivu.elect.business.sitzberechnung.control.verteilung.TeilnehmerErgebnis;

/**
 * Das Ergebnis der Verteilung nach Hare-Niemeyer für einen der Teilnehmer. Dieses beinhaltet die Anzahl Sitze aus Abrundung, Restsitzverteilung und (ggf. auf die Hare-Niemeyer-Verteilung folgend)
 * Losverfahren. Es ist Teil eines {@link DHondtErgebnis}es. Einzige spätere Modifikation (nach der eigentlichen Verteilung) kann durch Verteilung bei Restegleichheit (meist per Los) mit der Methode
 * {@link #entscheideLosverfahren(long)} erfolgen.
 */
public class DHondtTeilnehmerErgebnis extends TeilnehmerErgebnis {

  public static final Comparator<DHondtTeilnehmerErgebnis> SORT_BY_NAECHSTER_QUOTIENT = (x, y) -> y.getNaechsterQuotient().compareTo(x.getNaechsterQuotient());

  /**
   * @return Ergebnis eines Teilnehmers, wenn keine richtige Verteilung stattgefunden hat
   */
  static DHondtTeilnehmerErgebnis ohneVerteilung(Teilnehmer teilnehmer) {
    return new DHondtTeilnehmerErgebnis(teilnehmer);
  }

  DHondtTeilnehmerErgebnis(Teilnehmer teilnehmer, Fraction divisor) {
    super(teilnehmer, divisor);
  }

  private DHondtTeilnehmerErgebnis(Teilnehmer teilnehmer) {
    super(teilnehmer);
  }

  public long getSitzeMinimal() {
    return getSitze();
  }

  public Fraction getNaechsterQuotient() {
    return Fraction.getFraction(teilnehmer.getStimmen(), getSitze() + 1);
  }

  public @Nullable Fraction getLetzterQuotient() {
    if (getSitze() > 0) {
      return Fraction.getFraction(teilnehmer.getStimmen(), getSitze());
    } else {
      return null;
    }
  }

  @Override
  protected void vergibRestsitz() {
    // Diese Methode gibt es nur, um zu verhindern, dass sie in der Oberklasse public sein muss.
    super.vergibRestsitz();
  }

  @Override
  protected void seiTeilnehmerAmLosverfahren() {
    // Diese Methode gibt es nur, um zu verhindern, dass sie in der Oberklasse public sein muss.
    super.seiTeilnehmerAmLosverfahren();
  }

  public List<DHondtQuotient> createDHondtQuotienten(long anzahlDHondtQuotienten) {
    List<DHondtQuotient> result = new ArrayList<>();
    long zaehler = getTeilnehmer().getStimmen();
    long sitze = getSitze();
    for (long nenner = 1; nenner <= anzahlDHondtQuotienten; nenner++) {
      // Der Teilnehmer für die Verteilung des Sitzes am Rang ist Teilnehmer im Losverfahren, wenn
      // - der Teilnehmer überhaupt Teilnehmer im Losverfahren ist und
      //   - der Teilnehmer einen Sitz per Los gewonnen hat, dann ist dies der letzte Sitz, also "Nenner == Anzahl Sitze", oder
      //   - der Teilnehmer keinen Sitz per Los gewonnen hat, dann ist dies der nächste Sitz, also "Nenner == Anzahl Sitze + 1".
      boolean isTeilnehmerAmLosverfahren = isTeilnehmerAmLosverfahren() && (getRestsitzeAusLosverfahren() > 0 && nenner == sitze || getRestsitzeAusLosverfahren() == 0 && nenner == sitze + 1);
      boolean isSitzgewinn = nenner <= sitze;
      result.add(new DHondtQuotient(this, zaehler, nenner, isSitzgewinn, isTeilnehmerAmLosverfahren));
    }
    return result;
  }
}
