
package de.ivu.elect.sitzberechnung.verteilung.dhondt;

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

import javax.annotation.Nullable;

import de.ivu.elect.sitzberechnung.math.Fraction;
import de.ivu.elect.sitzberechnung.math.FractionConverter;
import de.ivu.elect.sitzberechnung.verteilung.Teilnehmer;
import de.ivu.elect.sitzberechnung.verteilung.TeilnehmerErgebnis;

/**
 * Das Ergebnis der Verteilung nach D’Hondt für einen der Teilnehmer. Dieses beinhaltet die Anzahl Sitze aus Abrundung, Restsitzverteilung und (ggf. auf die 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 {

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

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

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

  public Fraction getNaechsterQuotient(FractionConverter fractionConverter) {
    return fractionConverter.asFractionConverted(getStimmen(), getSitze() + 1);
  }

  @Nullable
  public Fraction getLetzterQuotient(FractionConverter fractionConverter) {
    if (getSitze() > 0) {
      return fractionConverter.asFractionConverted(getStimmen(), getSitze());
    }

    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 anzahlStimmen = getStimmen();
    long anzahlSitze = 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 == anzahlSitze || getRestsitzeAusLosverfahren() == 0 && nenner == anzahlSitze + 1);
      boolean isSitzgewinn = nenner <= anzahlSitze;

      result.add(new DHondtQuotient(this, anzahlStimmen, nenner, isSitzgewinn, isTeilnehmerAmLosverfahren));
    }

    return result;
  }

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