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

import static java.util.Collections.emptyList;
import static java.util.Collections.reverseOrder;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.function.Function;

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.VerteilungContext;

/**
 * "Der Zuteilungsdivisor ist so zu bestimmen, dass insgesamt so viele Sitze verteilt werden, wie Sitze zu vergeben sind. Dazu wird zunächst die Gesamtzahl aller Stimmen durch die Gesamtzahl der zu
 * vergebenden Sitze geteilt. Werden danach mehr Sitze verteilt als Sitze zu vergeben sind, ist der Zuteilungsdivisor so heraufzusetzen, dass sich bei der Berechnung die zu vergebende Sitzzahl ergibt;
 * zur Bestimmung des höheren Zuteilungsdivisors wird die Gesamtzahl der abgegebenen Stimmen jeweils durch ihre um 0,5 verringerte Sitzzahl, die im vorausgegangenen Berechnungsschritt ermittelt wurde,
 * geteilt. Als neuer Zuteilungsdivisor wird der Mittelwert zwischen dem kleinsten und zweitkleinsten Divisorkandidaten bestimmt. Sofern zwei oder mehr Divisorkandidaten den gleichen Wert haben, ist
 * deren Zahl als neuer Zuteilungsdivisor zu bestimmen."
 *
 * @see SainteLagueHoechstzahlErgebnis#getDivisorInterval
 */
public class SainteLagueDivisorBerechnung {

  private final FractionConverter fractionConverter;

  public SainteLagueDivisorBerechnung() {
    this(FractionConverter.convertingExakt());
  }

  public SainteLagueDivisorBerechnung(FractionConverter fractionConverter) {
    super();

    this.fractionConverter = fractionConverter;
  }

  public SainteLagueDivisorBerechnungErgebnis berechneDivisor(long anzahlSitze, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    VerteilungContext context = new VerteilungContext(fractionConverter, anzahlSitze, teilnehmerInVerteilung);

    if (context.getAnzahlSitze() == 0) {
      return berechneDivisorKeineSitze(context, teilnehmerInVerteilung);
    }

    if (context.getAnzahlStimmenGesamt() == 0) {
      return berechneDivisorKeineStimmen(context, teilnehmerInVerteilung);
    }

    return berechneDivisor(context, teilnehmerInVerteilung);
  }

  private SainteLagueDivisorBerechnungErgebnis berechneDivisorKeineSitze(VerteilungContext context, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    return new SainteLagueDivisorBerechnungErgebnis(context, Fraction.ZERO, Fraction.ZERO, emptyList());
  }

  private SainteLagueDivisorBerechnungErgebnis berechneDivisorKeineStimmen(VerteilungContext context, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    return new SainteLagueDivisorBerechnungErgebnis(context, Fraction.ZERO, Fraction.ZERO, emptyList());
  }

  private SainteLagueDivisorBerechnungErgebnis berechneDivisor(VerteilungContext context, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    FractionConverter fractionConverter = context.getFractionConverter();

    Fraction divisorInitial = fractionConverter.asFractionConverted(context.getHareQuote());
    Fraction divisorFinal = divisorInitial;

    List<SainteLagueDivisorBerechnungSchritt> schritte = berechneDivisorIterativ(context, new ArrayList<>(), context.getAnzahlSitze(), teilnehmerInVerteilung, divisorInitial, divisorInitial);

    if (!schritte.isEmpty()) {
      divisorFinal = schritte.get(schritte.size() - 1).getDivisor();
    }

    return new SainteLagueDivisorBerechnungErgebnis(context, divisorInitial, divisorFinal, schritte);
  }

  private List<SainteLagueDivisorBerechnungSchritt> berechneDivisorIterativ(VerteilungContext context, List<SainteLagueDivisorBerechnungSchritt> schritte, long anzahlSitzeZuVerteilen,
      List< ? extends Teilnehmer> teilnehmerInVerteilung, Fraction divisorMin, Fraction divisorMax) {
    FractionConverter fractionConverter = context.getFractionConverter();

    Fraction divisor = fractionConverter.asFractionConverted(divisorMin.add(divisorMax), 2L); // "Als neuer Zuteilungsdivisor wird der Mittelwert zwischen dem kleinsten und zweitkleinsten Divisorkandidaten bestimmt."...
    long anzahlSitzeVerteilt = 0L;

    List<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisse = new ArrayList<>();

    for (Teilnehmer teilnehmer : teilnehmerInVerteilung) {
      long anzahlStimmen = teilnehmer.getStimmen();
      Fraction quote = fractionConverter.asFractionConverted(anzahlStimmen, divisor);
      long anzahlSitze = Math.round(quote.doubleValue());

      double anzahlSitzeDekrementiert = anzahlSitze - 0.5D;
      double anzahlSitzeInkrementiert = anzahlSitze + 0.5D;

      Fraction divisorKandidatAnzahlSitzeDekrementiert = Fraction.ZERO;
      Fraction divisorKandidatAnzahlSitzeInkrementiert = Fraction.ZERO;

      if (anzahlSitzeDekrementiert > 0) {
        divisorKandidatAnzahlSitzeDekrementiert = fractionConverter.asFractionConverted(anzahlStimmen, Fraction.getFraction(anzahlSitzeDekrementiert));
      }

      if (anzahlSitzeInkrementiert > 0) {
        divisorKandidatAnzahlSitzeInkrementiert = fractionConverter.asFractionConverted(anzahlStimmen, Fraction.getFraction(anzahlSitzeInkrementiert));
      }

      teilnehmerErgebnisse.add(new SainteLagueDivisorBerechnungTeilnehmerErgebnis(teilnehmer, anzahlStimmen, quote, anzahlSitze, anzahlSitzeDekrementiert, divisorKandidatAnzahlSitzeDekrementiert,
          anzahlSitzeInkrementiert, divisorKandidatAnzahlSitzeInkrementiert));

      anzahlSitzeVerteilt += anzahlSitze;
    }

    List<SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat> divisorKandidaten = new ArrayList<>();

    boolean divisorKandidatenAnzahlSitzeDekrementieren = anzahlSitzeZuVerteilen < anzahlSitzeVerteilt;
    boolean divisorKandidatenAnzahlSitzeInkrementieren = anzahlSitzeZuVerteilen > anzahlSitzeVerteilt;

    Entry<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> teilnehmerErgebnissePerDivisorKandidatMin = null;
    Entry<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> teilnehmerErgebnissePerDivisorKandidatMax = null;

    if (divisorKandidatenAnzahlSitzeDekrementieren) { // "Neuer Divisor wird der Mittelwert zwischen dem kleinsten und zweitkleinsten Divisorkandidaten"...
      SortedMap<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> teilnehmerErgebnissePerDivisorKandidatSortedAsc = collecTeilnehmerErgebnissePerDivisorKandidatSortedAsc(
          teilnehmerErgebnisse, SainteLagueDivisorBerechnungTeilnehmerErgebnis::getDivisorKandidatAnzahlSitzeDekrementiert);

      for (Entry<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> entry : teilnehmerErgebnissePerDivisorKandidatSortedAsc.entrySet()) {
        if (entry.getKey().compareTo(Fraction.ZERO) > 0) {
          if (teilnehmerErgebnissePerDivisorKandidatMin == null) { // Kleinster...
            teilnehmerErgebnissePerDivisorKandidatMin = entry;

            if (entry.getValue().size() > 1) { // "Sofern zwei oder mehr Divisorkandidaten den gleichen Wert haben, ist deren Zahl als neuer Zuteilungsdivisor zu bestimmen."...
              teilnehmerErgebnissePerDivisorKandidatMax = entry;
            }
          } else if (teilnehmerErgebnissePerDivisorKandidatMax == null) { // Zweitkleinster...
            teilnehmerErgebnissePerDivisorKandidatMax = entry;
          } else {
            break; // Fertig...
          }
        }
      }

      if (teilnehmerErgebnissePerDivisorKandidatMax == null) {
        teilnehmerErgebnissePerDivisorKandidatMax = teilnehmerErgebnissePerDivisorKandidatMin;
      }

      if (teilnehmerErgebnissePerDivisorKandidatMin != null && teilnehmerErgebnissePerDivisorKandidatMax != null) {
        Collection<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisseDivisorKandidatAusgewaehlt = new HashSet<>();
        teilnehmerErgebnisseDivisorKandidatAusgewaehlt.addAll(teilnehmerErgebnissePerDivisorKandidatMin.getValue());
        teilnehmerErgebnisseDivisorKandidatAusgewaehlt.addAll(teilnehmerErgebnissePerDivisorKandidatMax.getValue());

        for (SainteLagueDivisorBerechnungTeilnehmerErgebnis teilnehmerErgebnis : teilnehmerErgebnisse) {
          divisorKandidaten.add(new SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat(teilnehmerErgebnis.getTeilnehmer(), teilnehmerErgebnis.getAnzahlSitzeDekrementiert(),
              teilnehmerErgebnis.getDivisorKandidatAnzahlSitzeDekrementiert(), teilnehmerErgebnisseDivisorKandidatAusgewaehlt.contains(teilnehmerErgebnis)));
        }
      }
    }

    if (divisorKandidatenAnzahlSitzeInkrementieren) { // "Neuer Divisor wird der Mittelwert zwischen dem größten und zweitgrößten Divisorkandidaten."...
      SortedMap<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> teilnehmerErgebnissePerDivisorKandidatSortedDesc = collecTeilnehmerErgebnissePerDivisorKandidatSortedDesc(
          teilnehmerErgebnisse, SainteLagueDivisorBerechnungTeilnehmerErgebnis::getDivisorKandidatAnzahlSitzeInkrementiert);

      for (Entry<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> entry : teilnehmerErgebnissePerDivisorKandidatSortedDesc.entrySet()) {
        if (entry.getKey().compareTo(Fraction.ZERO) > 0) {
          if (teilnehmerErgebnissePerDivisorKandidatMax == null) { // Größter...
            teilnehmerErgebnissePerDivisorKandidatMax = entry;

            if (entry.getValue().size() > 1) { // "Sofern zwei oder mehr Divisorkandidaten den gleichen Wert haben, ist deren Zahl als neuer Zuteilungsdivisor zu bestimmen."...
              teilnehmerErgebnissePerDivisorKandidatMin = entry;
            }
          } else if (teilnehmerErgebnissePerDivisorKandidatMin == null) { // Zweitgrößter...
            teilnehmerErgebnissePerDivisorKandidatMin = entry;
          } else {
            break; // Fertig...
          }
        }
      }

      if (teilnehmerErgebnissePerDivisorKandidatMin == null) {
        teilnehmerErgebnissePerDivisorKandidatMin = teilnehmerErgebnissePerDivisorKandidatMax;
      }

      if (teilnehmerErgebnissePerDivisorKandidatMin != null && teilnehmerErgebnissePerDivisorKandidatMax != null) {
        Collection<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisseDivisorKandidatAusgewaehlt = new HashSet<>();
        teilnehmerErgebnisseDivisorKandidatAusgewaehlt.addAll(teilnehmerErgebnissePerDivisorKandidatMin.getValue());
        teilnehmerErgebnisseDivisorKandidatAusgewaehlt.addAll(teilnehmerErgebnissePerDivisorKandidatMax.getValue());

        for (SainteLagueDivisorBerechnungTeilnehmerErgebnis teilnehmerErgebnis : teilnehmerErgebnisse) {
          divisorKandidaten.add(new SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat(teilnehmerErgebnis.getTeilnehmer(), teilnehmerErgebnis.getAnzahlSitzeInkrementiert(),
              teilnehmerErgebnis.getDivisorKandidatAnzahlSitzeInkrementiert(), teilnehmerErgebnisseDivisorKandidatAusgewaehlt.contains(teilnehmerErgebnis)));
        }
      }
    }

    if (teilnehmerErgebnissePerDivisorKandidatMin != null && teilnehmerErgebnissePerDivisorKandidatMax != null) {
      Fraction divisorMinNext = teilnehmerErgebnissePerDivisorKandidatMin.getKey();
      Fraction divisorMaxNext = teilnehmerErgebnissePerDivisorKandidatMax.getKey();

      boolean divisorKandidatenUnveraendert = divisorMinNext.compareTo(divisorMin) == 0 && divisorMaxNext.compareTo(divisorMax) == 0;

      SainteLagueDivisorBerechnungSchritt schritt = new SainteLagueDivisorBerechnungSchritt(divisorMin, divisorMax, divisor, anzahlSitzeZuVerteilen, anzahlSitzeVerteilt, teilnehmerErgebnisse,
          divisorKandidaten, divisorKandidatenAnzahlSitzeDekrementieren, divisorKandidatenAnzahlSitzeInkrementieren, divisorKandidatenUnveraendert);
      schritte.add(schritt);

      if (divisorKandidatenUnveraendert) {
        /*
         * NEUE UND ALTE DIVISORKANDIDATEN SIND IDENTISCH -> WEITERRECHNEN BRINGT NICHTS!!!
         *
         * Die Existenz neuer Divisorkandidaten impliziert, dass zuviel oder zuwenig Sitze verteilt wurden. Das wiederum bedeutet, dass in der anschließenden Verteilung (mit dem aktuellen
         * Zuteilungsdivisor) ein Losentscheid erforderlich sein wird...
         */
      } else {
        berechneDivisorIterativ(context, schritte, anzahlSitzeZuVerteilen, teilnehmerInVerteilung, divisorMinNext, divisorMaxNext);
      }
    } else {
      boolean divisorKandidatenUnveraendert = false;

      SainteLagueDivisorBerechnungSchritt schritt = new SainteLagueDivisorBerechnungSchritt(divisorMin, divisorMax, divisor, anzahlSitzeZuVerteilen, anzahlSitzeVerteilt, teilnehmerErgebnisse,
          divisorKandidaten, divisorKandidatenAnzahlSitzeDekrementieren, divisorKandidatenAnzahlSitzeInkrementieren, divisorKandidatenUnveraendert);
      schritte.add(schritt);
    }

    return schritte;
  }

  private SortedMap<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> collecTeilnehmerErgebnissePerDivisorKandidatSortedDesc(
      List<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisse, Function<SainteLagueDivisorBerechnungTeilnehmerErgebnis, Fraction> classifier) {
    SortedMap<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> result = new TreeMap<>(reverseOrder());
    result.putAll(collecTeilnehmerErgebnissePerDivisorKandidatSortedAsc(teilnehmerErgebnisse, classifier));

    return result;
  }

  private SortedMap<Fraction, List<SainteLagueDivisorBerechnungTeilnehmerErgebnis>> collecTeilnehmerErgebnissePerDivisorKandidatSortedAsc(
      List<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisse, Function<SainteLagueDivisorBerechnungTeilnehmerErgebnis, Fraction> classifier) {
    return teilnehmerErgebnisse.stream().collect(groupingBy(classifier, TreeMap::new, toList()));
  }

  public static final class SainteLagueDivisorBerechnungErgebnis {

    private final VerteilungContext context;

    private final Fraction divisorInitial;

    private final Fraction divisorFinal;

    private final List<SainteLagueDivisorBerechnungSchritt> schritte;

    SainteLagueDivisorBerechnungErgebnis(VerteilungContext context, Fraction divisorInitial, Fraction divisorFinal, List<SainteLagueDivisorBerechnungSchritt> schritte) {
      super();

      this.context = context;

      this.divisorInitial = divisorInitial;
      this.divisorFinal = divisorFinal;

      this.schritte = unmodifiableList(schritte);
    }

    public long getAnzahlSitze() {
      return context.getAnzahlSitze();
    }

    public long getAnzahlStimmenGesamt() {
      return context.getAnzahlStimmenGesamt();
    }

    public Fraction getDivisorInitial() {
      return divisorInitial;
    }

    public Fraction getDivisorFinal() {
      return divisorFinal;
    }

    public List<SainteLagueDivisorBerechnungSchritt> getSchritte() {
      return schritte;
    }
  }

  public static final class SainteLagueDivisorBerechnungSchritt {

    private final Fraction divisorMin;

    private final Fraction divisorMax;

    private final Fraction divisor;

    private final long anzahlSitzeZuVerteilen;

    private final long anzahlSitzeVerteilt;

    private final List<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisse;

    private final List<SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat> divisorKandidaten;

    private final boolean divisorKandidatenAnzahlSitzeDekrementiert;

    private final boolean divisorKandidatenAnzahlSitzeInkrementiert;

    private final boolean divisorKandidatenUnveraendert;

    SainteLagueDivisorBerechnungSchritt(Fraction divisorMin, Fraction divisorMax, Fraction divisor, long anzahlSitzeZuVerteilen, long anzahlSitzeVerteilt,
        List<SainteLagueDivisorBerechnungTeilnehmerErgebnis> teilnehmerErgebnisse, List<SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat> divisorKandidaten,
        boolean divisorKandidatenAnzahlSitzeDekrementiert, boolean divisorKandidatenAnzahlSitzeInkrementiert, boolean divisorKandidatenUnveraendert) {
      super();

      this.divisorMin = divisorMin;
      this.divisorMax = divisorMax;
      this.divisor = divisor;

      this.anzahlSitzeZuVerteilen = anzahlSitzeZuVerteilen;
      this.anzahlSitzeVerteilt = anzahlSitzeVerteilt;

      this.teilnehmerErgebnisse = unmodifiableList(teilnehmerErgebnisse);

      this.divisorKandidaten = unmodifiableList(divisorKandidaten);
      this.divisorKandidatenAnzahlSitzeDekrementiert = divisorKandidatenAnzahlSitzeDekrementiert;
      this.divisorKandidatenAnzahlSitzeInkrementiert = divisorKandidatenAnzahlSitzeInkrementiert;

      this.divisorKandidatenUnveraendert = divisorKandidatenUnveraendert;
    }

    public Fraction getDivisorMin() {
      return divisorMin;
    }

    public Fraction getDivisorMax() {
      return divisorMax;
    }

    public Fraction getDivisor() {
      return divisor;
    }

    public long getAnzahlSitzeZuVerteilen() {
      return anzahlSitzeZuVerteilen;
    }

    public long getAnzahlSitzeVerteilt() {
      return anzahlSitzeVerteilt;
    }

    public long getAnzahlSitzeVerteiltDifferenz() {
      return getAnzahlSitzeVerteilt() - getAnzahlSitzeZuVerteilen();
    }

    public List<SainteLagueDivisorBerechnungTeilnehmerErgebnis> getTeilnehmerErgebnisse() {
      return teilnehmerErgebnisse;
    }

    public List<SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat> getDivisorKandidaten() {
      return divisorKandidaten;
    }

    /**
     * @return true, falls in diesem Schritt die Divisorkandidaten der Teilnehmer verwendet wurden, bei denen die Anzahl Sitze DEKREMENTIERT (-0,5) wurde.
     */
    public boolean isDivisorKandidatenAnzahlSitzeDekrementiert() {
      return divisorKandidatenAnzahlSitzeDekrementiert;
    }

    /**
     * @return true, falls in diesem Schritt die Divisorkandidaten der Teilnehmer verwendet wurden, bei denen die Anzahl Sitze INKREMENTIERT (+0,5) wurde.
     */
    public boolean isDivisorKandidatenAnzahlSitzeInkrementiert() {
      return divisorKandidatenAnzahlSitzeInkrementiert;
    }

    /**
     * SPEZIALFALL, der einen Losentscheid bei einer anschließenden Verteilung impliziert!!!
     *
     * @return true, falls in diesem Schritt dieselben Divisorkandidaten wie im vorherigen Schritt berechnet wurden.
     */
    public boolean isDivisorKandidatenUnveraendert() {
      return divisorKandidatenUnveraendert;
    }
  }

  public static final class SainteLagueDivisorBerechnungTeilnehmerErgebnis {

    private final Teilnehmer teilnehmer;

    private final long anzahlStimmen;

    private final Fraction quote;

    private final long anzahlSitze;

    private final double anzahlSitzeDekrementiert;

    private final Fraction divisorKandidatAnzahlSitzeDekrementiert;

    private final double anzahlSitzeInkrementiert;

    private final Fraction divisorKandidatAnzahlSitzeInkrementiert;

    SainteLagueDivisorBerechnungTeilnehmerErgebnis(Teilnehmer teilnehmer, long anzahlStimmen, Fraction quote, long anzahlSitze, double anzahlSitzeDekrementiert,
        Fraction divisorKandidatAnzahlSitzeDekrementiert, double anzahlSitzeInkrementiert, Fraction divisorKandidatAnzahlSitzeInkrementiert) {
      super();

      this.teilnehmer = teilnehmer;

      this.anzahlStimmen = anzahlStimmen;

      this.quote = quote;

      this.anzahlSitze = anzahlSitze;

      this.anzahlSitzeDekrementiert = anzahlSitzeDekrementiert;
      this.divisorKandidatAnzahlSitzeDekrementiert = divisorKandidatAnzahlSitzeDekrementiert;

      this.anzahlSitzeInkrementiert = anzahlSitzeInkrementiert;
      this.divisorKandidatAnzahlSitzeInkrementiert = divisorKandidatAnzahlSitzeInkrementiert;
    }

    public Teilnehmer getTeilnehmer() {
      return teilnehmer;
    }

    public long getAnzahlStimmen() {
      return anzahlStimmen;
    }

    public Fraction getQuote() {
      return quote;
    }

    public long getAnzahlSitze() {
      return anzahlSitze;
    }

    public double getAnzahlSitzeDekrementiert() {
      return anzahlSitzeDekrementiert;
    }

    /**
     * @return (Pauschal berechnete) Divisorkandidaten des Teilnehmers, bei denen die Anzahl Sitze DEKREMENTIERT (-0,5) wurde.
     */
    public Fraction getDivisorKandidatAnzahlSitzeDekrementiert() {
      return divisorKandidatAnzahlSitzeDekrementiert;
    }

    public double getAnzahlSitzeInkrementiert() {
      return anzahlSitzeInkrementiert;
    }

    /**
     * @return (Pauschal berechnete) Divisorkandidaten des Teilnehmers, bei denen die Anzahl Sitze INKREMENTIERT (+0,5) wurde.
     */
    public Fraction getDivisorKandidatAnzahlSitzeInkrementiert() {
      return divisorKandidatAnzahlSitzeInkrementiert;
    }
  }

  public static final class SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat {

    private final Teilnehmer teilnehmer;

    private final long anzahlStimmen;

    private final double anzahlSitze;

    private final Fraction divisor;

    private final boolean ausgewaehlt;

    SainteLagueDivisorBerechnungTeilnehmerDivisorKandidat(Teilnehmer teilnehmer, double anzahlSitze, Fraction divisor, boolean ausgewaehlt) {
      super();

      this.teilnehmer = teilnehmer;

      this.anzahlStimmen = teilnehmer.getStimmen();

      this.anzahlSitze = anzahlSitze;

      this.divisor = divisor;

      this.ausgewaehlt = ausgewaehlt;
    }

    public Teilnehmer getTeilnehmer() {
      return teilnehmer;
    }

    public long getAnzahlStimmen() {
      return anzahlStimmen;
    }

    public double getAnzahlSitze() {
      return anzahlSitze;
    }

    public Fraction getDivisor() {
      return divisor;
    }

    public boolean isAusgewaehlt() {
      return ausgewaehlt;
    }
  }
}
