package de.ivu.elect.dokumente.ergebnis.adapter;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.gruppe.entity.GruppePK;
import de.ivu.elect.business.person.entity.PersonendatenPK;
import de.ivu.elect.business.sitzberechnung.entity.OsvLegacyErgebnisKonfliktArt;
import de.ivu.elect.business.sitzberechnung.entity.OsvLegacyKonfliktCustomData;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagPK;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.AllgemeineListe;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.BesonderheitBeiNominierungDerGewaehlten;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.DHondtQuotient;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.DHondtSitzverteilung;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.OSVLegacyErgebnisDaten;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.Unterverteilung;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.VerteilungTyp;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.Zuteilung;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.ZuteilungInVerteilung;
import de.ivu.elect.sitzberechnung.osv.exchange.p22.ZuteilungTyp;

/*
*
* Vorlage: nl-sitzberechung#de.ivu.elect.sitzberechnung.osv.exchange.p22.NlErgebnisDaten2ErgebnisDokumentAdapter
*
* */
public class NlErgebnisDaten2ErgebnisDokumentAdapter {

  private static final Logger LOG = LoggerFactory.getLogger(NlErgebnisDaten2ErgebnisDokumentAdapter.class);

  private final OSVLegacyErgebnisDaten osvLegacyErgebnisDaten;
  private final List<OsvLegacyKonfliktCustomData> konflikte;

  public static NlErgebnisDaten2ErgebnisDokumentAdapter EMPTY_OBJECT =
          new NlErgebnisDaten2ErgebnisDokumentAdapter(new OSVLegacyErgebnisDaten(), Collections.emptyList());

  public NlErgebnisDaten2ErgebnisDokumentAdapter(
          OSVLegacyErgebnisDaten osvLegacyErgebnisDaten,
          List<ErgebnisKonflikt> konflikte) {
    this.osvLegacyErgebnisDaten = osvLegacyErgebnisDaten;
    this.konflikte = konflikte.stream()
            .map(k -> k.getCustomData(OsvLegacyKonfliktCustomData.class))
            .collect(Collectors.toList());
  }

  /**
   * P22-1, Kap. 7 oder P22-2, Kap. 8
   */
  public Fraction getWahlteiler() {
    return new Fraction(osvLegacyErgebnisDaten.getAnzahlStimmen(), osvLegacyErgebnisDaten.getAnzahlSitze());
  }

  /**
   * P22-1, Kap. 8 oder P22-2, Kap. 9, "aantal volle zetels"
   */
  public long getAnzahlSitzeAusErsterZuteilung(GruppePK gruppe) {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.ERSTE_ZUTEILUNG)
            .filter(anGruppe(gruppe))
            .mapToLong(Zuteilung::getSitze)
            .findAny()
            .orElse(0L);
  }

  /**
   * P22-1, Kap. 8 oder P22-2, Kap. 9, "Totaal aantal zetels"
   */
  public long getAnzahlSitzeZuVerteilenBeiErsterZuteilung() {
    return osvLegacyErgebnisDaten.getAnzahlSitze();
  }

  /**
   * P22-1, Kap. 8 oder P22-2, Kap. 9, "Totaal aantal toegewesen volle zetels"
   */
  public long getGesamtzahlSitzeAusErsterZuteilung() {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.ERSTE_ZUTEILUNG)
            .mapToLong(Zuteilung::getSitze).sum();
  }

  /**
   * P22-1, Kap. 8 oder P22-2, Kap. 9, "Restzetels"
   */
  public long getAnzahlRestsitzeNachErsterZuteilung() {
    return getAnzahlSitzeZuVerteilenBeiErsterZuteilung() - getGesamtzahlSitzeAusErsterZuteilung();
  }

  /**
   * P22-2, Kap. 10: "aantal volle zetels per lijst", Oberverteilung nach Hare-Niemeyer
   */
  public long getAnzahlSitzeAusErsterZuteilungFuerGruppeInOberverteilung(GruppePK gruppe) {
    return getAnzahlSitzeAusErsterZuteilung(gruppe);
  }

  /**
   * P22-2, Kap. 10: "overschot", Oberverteilung nach Hare-Niemeyer
   */
  public Fraction getRestNachErsterZuteilungFuerGruppeInOberverteilung(GruppePK gruppe) {
    Stream<Zuteilung> zuteilungenAusErsterZuteilungStream = getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.ERSTE_ZUTEILUNG)
            .filter(anGruppe(gruppe));
    return getRestNachErsterZuteilung(zuteilungenAusErsterZuteilungStream);
  }

  /**
   * P22-2, Kap. 10: "toegewezen aantal restzetels", Oberverteilung nach Hare-Niemeyer
   */
  public long getAnzahlSitzeAusNiemeyerVerteilungFuerGruppeInOberverteilung(GruppePK gruppe) {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.NIEMEYER_ZUTEILUNG)
            .filter(anGruppe(gruppe))
            .mapToLong(Zuteilung::getSitze)
            .sum();
  }

  /**
   * P22-2, Kap. 10: "totaal aantal zetels", Oberverteilung nach Hare-Niemeyer
   */
  public long getGesamtzahlSitzeNachNiemeyerVerteilungFuerGruppeInOberverteilung(GruppePK gruppe) {
    return getAnzahlSitzeAusErsterZuteilungFuerGruppeInOberverteilung(gruppe)
            + getAnzahlSitzeAusNiemeyerVerteilungFuerGruppeInOberverteilung(gruppe);
  }

  /**
   * P22-2, Kap. 10, Losen bei Oberverterteilung nach Hare-Niemeyer
   */
  public List<OsvLegacyKonfliktCustomData> getKonflikteBeiOberverteilungNachHareNiemeyer() {
    return getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt.NIEMEYER_P3)
            .collect(Collectors.toList());
  }

  /**
   * P22-2, Kap. 10, Anzahl Restsitze, die nach einer Verteilung nach Hare-Neimeyer aber vor einer anschließenden d'Hondt-Verteilung noch unbesetzt waren.
   * <p>
   * "Hierna waren er nog ... restzetels te verdelen. Deze zetels zijn toegewezen aan de lijsten
   * die met een zetel erbij het grootste gemiddelde aantal stemmen per zetel hebben.
   * Hierbij heeft iedere lijst niet meer dan één zetel toegewezen gekregen", siehe OSV-1481
   */
  public int getAnzahlUnbesetzteRestsitzeVorOberverteilungNachDHondt() {
    return getDHondtSitzverteilungenBeiOberverteilungStream()
            .mapToInt(DHondtSitzverteilung::getSitzeGesamtZuVerteilen)
            .findAny()
            .orElse(0);
  }

  /**
   * P22-2, Kap. 10, d’Hondt-Verteilung beschränkt auf einen Sitz pro Liste, diejenigen Gruppen, die in der Tabelle vorkommen dürfen
   */
  public Boolean isTeilnehmerAnDHondtVerteilungBeschraenktAufEinenSitzOberverteilung(GruppePK gruppePk) {
    return getDHondtSitzverteilungenBeiOberverteilungStream()
            .anyMatch(dHondtSitzverteilung ->  dHondtSitzverteilung.getVerteilungAn().getGruppeKey().equals(gruppePk.toString()));
  }

  /**
   * P22-2, Kap. 10, d’Hondt-Verteilung beschränkt auf einen Sitz pro Liste, Spalte "Reeds toegewezen aantal zetels"
   */
  public Long getSitzeVorDHondtVerteilungBeschraenktAufEinenSitzOberverteilung(GruppePK gruppe) {
    return getDHondtSitzverteilungenBeiOberverteilungStream()
            .filter(anGruppe(gruppe))
            .mapToLong(dHondtSitzverteilung -> (long) dHondtSitzverteilung.getSitze())
            .findAny()
            .orElseThrow(() -> new IllegalArgumentException("Die Gruppe nimmt nicht an der d'Hondt-Verteilung teil: " + gruppe));
  }

  /**
   * P22-2, Kap. 10, d’Hondt-Verteilung beschränkt auf einen Sitz pro Liste, Spalte "Gemiddeld aantal stemmen bij toewijzing restzetel"
   */
  public Fraction getDHondtQuotientBeschraenktAufEinenSitzOberverteilung(GruppePK gruppe) {
    int lauf = 1; // Es werden die Quotienten ausgegeben, die für den ersten Lauf relevant waren, egal wieviele Läufe es gab
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiOberverteilungStream()
            .filter(anGruppe(gruppe));
    DHondtQuotient dHondtQuotient = getDHondtZuteilungInLauf(lauf, stream)
            .orElseThrow(() -> new IllegalArgumentException("Die Gruppe nimmt nicht an der d'Hondt-Verteilung teil: " + gruppe));
    return getDHondtQuotient(dHondtQuotient);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Anzahl der "restzetel"-Spalten, siehe OSV-1481
   */
  public int getAnzahlLaeufeOberverteilungNachDHondt() {
    return getAnzahlLaeufe(getDHondtSitzverteilungenBeiOberverteilungStream());
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Brüche in der Tabelle
   *
   * @param lauf 1-basierter Index der d'Hondt-Schritte bei der Oberverteilung, also zwischen 1 und getAnzahlVerteilungsschritteOberverteilungNachDHondt()
   */
  public Fraction getDHondtQuotientOberverteilung(GruppePK gruppe, int lauf) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiOberverteilungStream()
            .filter(anGruppe(gruppe));
    DHondtQuotient dHondtQuotient = getDHondtZuteilungInLauf(lauf, stream).orElse(null);
    return getDHondtQuotient(dHondtQuotient);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Information, welcher Bruch zu einem Sitzgewinn geführt hat (Darstellung in Fettdruck)
   *
   * @param lauf 1-basierter Index der d'Hondt-Schritte bei der Oberverteilung, also zwischen 1 und getAnzahlVerteilungsschritteOberverteilungNachDHondt()
   */
  public boolean isSitzgewinnImLaufInOberverteilungNachDHondt(GruppePK gruppe, int lauf) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiOberverteilungStream()
            .filter(anGruppe(gruppe));
    return isSitzgewinnNachDHondtImLauf(lauf, stream);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Spalte "aantal restzetels"
   */
  public long getAnzahlRestsitzeAusOberverteilungNachDHondt(GruppePK gruppe) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiOberverteilungStream().filter(anGruppe(gruppe));
    return getAnzahlRestsitzeNachDHondt(stream);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Untere Zeile "Restzetel toegekend aan lijst"
   * <p>
   * In jedem Lauf wird nur ein Sitz zugewiesen. Falls in einem Schritt bei der Verteilung mehrere Sitz zugleich
   * zugewiesen werden, so wird das in mehrere Läufe unterteilt, siehe OSV-1458, issue 4.
   *
   * @return wählt aus den gegebenen gruppen diejenige aus, die im gegebenen lauf einen Sitz gewonnen hat
   */
  public GruppePK getDHondtGewinnerOberverteilung(Collection<GruppePK> gruppen, int lauf) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiOberverteilungStream();
    AllgemeineListe sitzgewinner = getDHondtGewinner(lauf, stream);
    return getGruppeMatching(gruppen, sitzgewinner);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Losen bei Oberverterteilung nach d'Hondt
   */
  public List<OsvLegacyKonfliktCustomData> getKonflikteBeiOberverteilungNachDHondt() {
    return getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt.DHONDT_P3)
            .collect(Collectors.toList());
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Mehrheitssicherungsklausel
   */
  public boolean kommtMehrheitssicherungsklauselZurAnwendung() {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.MEHRHEITSSICHERUNGSKLAUSEL)
            .findAny()
            .isPresent();
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Mehrheitssicherungsklausel mit Losentscheid
   */
  public boolean hatLosentscheidBeiMehrheitssicherungsklausel() {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.MEHRHEITSSICHERUNGSKLAUSEL)
            .anyMatch(Zuteilung::getLosentscheid);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Losen bei der Entscheidung, wer wegen Mehrheitssicherungsklausel einen Sitz verliert
   */
  public Optional<OsvLegacyKonfliktCustomData> getKonfliktBeiMehrheitssicherungsklausel() {
    return getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt.ABSOLUTE_MAJORITY)
            .findAny();
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, die Liste, die durch Mehrheitssicherungsklausel einen Sitz gewinnt
   */
  public GruppePK getGewinnerBeiMehrheitssicherungsklausel(Collection<GruppePK> gruppen) {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.MEHRHEITSSICHERUNGSKLAUSEL)
            .filter(zuteilung -> zuteilung.getSitze() > 0)
            .map(zuteilung -> getGruppeMatching(gruppen, zuteilung.getVerteilungAn()))
            .findAny()
            .orElse(null);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, die Liste, die durch Mehrheitssicherungsklausel einen Sitz verliert
   */
  public GruppePK getVerliererBeiMehrheitssicherungsklausel(Collection<GruppePK> gruppen) {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.MEHRHEITSSICHERUNGSKLAUSEL)
            .filter(zuteilung -> zuteilung.getSitze() < 0)
            .map(zuteilung -> getGruppeMatching(gruppen, zuteilung.getVerteilungAn()))
            .findAny()
            .orElse(null);
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10, Listen, die um den Sitzverlust wegen Mehrheitssicherungsklausel an einem Losentscheid teilgenommen haben und keinen Sitz verloren haben.
   */
  public List<GruppePK> getLosentscheidTeilnehmerBeiMehrheitssicherungsklauselOhneSitzverlust(Collection<GruppePK> gruppen) {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.MEHRHEITSSICHERUNGSKLAUSEL)
            .filter(Zuteilung::getLosentscheid)
            .filter(zuteilung -> zuteilung.getSitze() == 0)
            .map(zuteilung -> getGruppeMatching(gruppen, zuteilung.getVerteilungAn()))
            .collect(Collectors.toList());
  }

  /**
   * P22-1, Kap. 9 oder P22-2, Kap. 10: Gibt an, welche Listen bei der Oberverteilung wie viele Sitze durch Listenerschöpfung verloren haben
   */
  public Map<GruppePK, Integer> getVonListenerschoepfungBeiOberverteilungBetroffeneGruppen(Collection<GruppePK> gruppenZurAuswahl) {
    return getZuteilungenStream(VerteilungTyp.OBERVERTEILUNG, ZuteilungTyp.LISTENERSCHOEPFUNG)
            .filter(zuteilung -> zuteilung.getSitze() != 0)
            .collect(Collectors.toMap(
                    zuteilung -> getGruppeMatching(gruppenZurAuswahl, zuteilung.getVerteilungAn()),
                    zuteilung -> -zuteilung.getSitze()));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: Gibt an, ob eine Unterverteilung in einer Liste erfolgt ist
   */
  public Boolean isGruppeMitUnterverteilung(GruppePK gruppe) {
    return osvLegacyErgebnisDaten.getUnterverteilungen().stream()
            .anyMatch(unterverteilung -> unterverteilung.getGruppeKey().equals(gruppe.toString()));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "Toegewezen aantal zetels lijstengroup" / "aantal zetels"
   */
  public OptionalLong getAnzahlSitze(GruppePK gruppe) {
    return osvLegacyErgebnisDaten.getUnterverteilungen().stream()
            .filter(unterverteilung -> isGruppeMitKey(gruppe, unterverteilung.getGruppeKey()))
            .mapToLong(Unterverteilung::getSitze)
            .findAny();
            //.orElseThrow(() -> new IllegalArgumentException("Zur Gruppe gibt es keine Unterverteilung: " + gruppe));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "aantal stemmen"
   */
  public OptionalLong getAnzahlStimmen(GruppePK gruppe) {
    return osvLegacyErgebnisDaten.getUnterverteilungen().stream()
            .filter(unterverteilung -> isGruppeMitKey(gruppe, unterverteilung.getGruppeKey()))
            .mapToLong(Unterverteilung::getStimmen)
            .findAny();
            //.orElseThrow(() -> new IllegalArgumentException("Zur Gruppe gibt es keine Unterverteilung: " + gruppe));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "groepskiesdeler"
   */
  public Optional<Fraction> getWahlteilerBeiUnterverteilungInGruppe(GruppePK gruppe) {
    OptionalLong anzahlStimmen = getAnzahlStimmen(gruppe);
    OptionalLong anzahlSitze = getAnzahlSitze(gruppe);
    if (anzahlSitze.isPresent() && anzahlStimmen.isPresent()) {
      return Optional.of(new Fraction(anzahlStimmen.getAsLong(), anzahlSitze.getAsLong()));
    }
    return Optional.empty();
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "lijst of stel gelijkluidende lijsten" (hier nur die Stels)
   */
/*  public List<Stel> getStelsBeiUnterverteilungInGruppe(GruppePK gruppe, Collection<Stel> stelsZurAuswahl) {
    return getErsteZuteilungInUnterverteilungInGruppe(gruppe)
            .map(zuteilung -> getStelMitKey(stelsZurAuswahl, zuteilung.getVerteilungAn().getStelKey()))
            .filter(Objects::nonNull)
            .sorted(Comparator.comparing(Stel::getKey))
            .collect(Collectors.toList());
  }*/

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "lijst of stel gelijkluidende lijsten" (hier nur die Listen)
   */
  public List<WahlvorschlagPK> getListenBeiUnterverteilungInGruppe(GruppePK gruppe, Collection<WahlvorschlagPK> listenZurAuswahl) {
    return getErsteZuteilungInUnterverteilungInGruppe(gruppe)
            .map(zuteilung -> getListeMitKey(listenZurAuswahl, zuteilung.getVerteilungAn().getListeKey()))
            .filter(Objects::nonNull)
            .sorted(Comparator.comparingLong(WahlvorschlagPK::getId))
            .collect(Collectors.toList());
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "aantal volle zetels per lijst" (hier für Stels)
   */
  public long getAnzahlSitzeAusErsterZuteilungFuerStelInGruppe(String stelId, GruppePK gruppe) {
    return getAnzahlSitzeAusErsterZuteilungFuerStelOderListeInGruppe(gruppe, anStel(stelId));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "aantal volle zetels per lijst" (hier für Listen)
   */
  public long getAnzahlSitzeAusErsterZuteilungFuerListeInGruppe(WahlvorschlagPK liste, GruppePK gruppe) {
    return getAnzahlSitzeAusErsterZuteilungFuerStelOderListeInGruppe(gruppe, anListe(liste));
  }

  private long getAnzahlSitzeAusErsterZuteilungFuerStelOderListeInGruppe(GruppePK gruppe,
                                                                         Predicate<ZuteilungInVerteilung> anStelOderListe) {
    return getErsteZuteilungInUnterverteilungInGruppe(gruppe)
            .filter(anStelOderListe)
            .mapToLong(Zuteilung::getSitze)
            .findAny()
            .orElse(0L);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "overschot" (hier für Stels)
   */
  public Fraction getRestNachErsterZuteilungFuerStelInGruppe(String stelId, GruppePK gruppe) {
    Stream<Zuteilung> stream = getErsteZuteilungInUnterverteilungInGruppe(gruppe)
            .filter(anStel(stelId));
    return getRestNachErsterZuteilung(stream);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "overschot" (hier für Listen)
   */
  public Fraction getRestNachErsterZuteilungFuerListeInGruppe(WahlvorschlagPK liste, GruppePK gruppe) {
    Stream<Zuteilung> stream = getErsteZuteilungInUnterverteilungInGruppe(gruppe)
            .filter(anListe(liste));
    return getRestNachErsterZuteilung(stream);
  }

  private Stream<Zuteilung> getErsteZuteilungInUnterverteilungInGruppe(GruppePK gruppe) {
    return getZuteilungenStream(VerteilungTyp.UNTERVERTEILUNG, ZuteilungTyp.ERSTE_ZUTEILUNG)
            .filter(innerhalbVonGruppe(gruppe));
  }

  private Fraction getRestNachErsterZuteilung(Stream<Zuteilung> zuteilungenAusErsterZuteilungStream) {
    return zuteilungenAusErsterZuteilungStream
            .map(zuteilung -> new Fraction(zuteilung.getZaehlerVomRest(), zuteilung.getNennerVomRest()))
            .findAny()
            .orElseGet(() -> { // ELECT-13521
              LOG.error("KEIN Rest nach erster Zuteilung bestimmbar");

              return Fraction.UNDEFINED;
            });
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "toegewezen aantal restzetels" (hier für Stels)
   */
  public long getAnzahlSitzeAusNiemeyerVerteilungFuerStelInGruppe(String stelId, GruppePK gruppe) {
    return getAnzahlSitzeAusNiemeyerVerteilungFuerStelOderListeInGruppe(gruppe, anStel(stelId));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "toegewezen aantal restzetels" (hier für Listen)
   */
  public long getAnzahlSitzeAusNiemeyerVerteilungFuerListeInGruppe(WahlvorschlagPK liste, GruppePK gruppe) {
    return getAnzahlSitzeAusNiemeyerVerteilungFuerStelOderListeInGruppe(gruppe, anListe(liste));
  }

  private long getAnzahlSitzeAusNiemeyerVerteilungFuerStelOderListeInGruppe(GruppePK gruppe,
                                                                            Predicate<ZuteilungInVerteilung> anStelOderListe) {
    return getZuteilungenStream(VerteilungTyp.UNTERVERTEILUNG, ZuteilungTyp.NIEMEYER_ZUTEILUNG)
            .filter(innerhalbVonGruppe(gruppe))
            .filter(anStelOderListe)
            .mapToLong(Zuteilung::getSitze)
            .sum();
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "totaal aantal zetels" (hier für Stels)
   */
  public long getGesamtzahlSitzeNachNiemeyerVerteilungFuerStelInGruppe(String stelId, GruppePK gruppe) {
    return getAnzahlSitzeAusErsterZuteilungFuerStelInGruppe(stelId, gruppe)
            + getAnzahlSitzeAusNiemeyerVerteilungFuerStelInGruppe(stelId, gruppe);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: "totaal aantal zetels" (hier für Listen)
   */
  public long getGesamtzahlSitzeNachNiemeyerVerteilungFuerListeInGruppe(WahlvorschlagPK liste, GruppePK gruppe) {
    return getAnzahlSitzeAusErsterZuteilungFuerListeInGruppe(liste, gruppe)
            + getAnzahlSitzeAusNiemeyerVerteilungFuerListeInGruppe(liste, gruppe);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Losen bei Unterverterteilung nach Hare-Niemeyer
   * <p>
   * Da man dem Konflikt nicht ansieht., in welcher Unterverteilung (in welcher GruppePK) er aufgetreten ist, muss das an Hand der Teilnehmenden Stels und Listen ermittelt werden
   */
//  public List<OsvLegacyKonfliktCustomData> getKonflikteBeiUnterverteilungNachHareNiemeyerZwischenStelsUndListen(
//          Collection<Stel> alleStelsDerGruppe, Collection<Liste> alleListenDerGruppe) {
//    return getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt.NIEMEYER_P2)
//            .filter(konflikt -> isKonfliktZwischen(konflikt, alleStelsDerGruppe, alleListenDerGruppe))
//            .collect(Collectors.toList());
//  }

//  private boolean isKonfliktZwischen(OsvLegacyKonfliktCustomData konflikt, Collection<Stel> alleStelsDerGruppe, Collection<Liste> alleListenDerGruppe) {
//    return isKonfliktZwischen(konflikt, alleStelsDerGruppe) || isKonfliktZwischen(konflikt, alleListenDerGruppe);
//  }

//  private boolean isKonfliktZwischen(OsvLegacyKonfliktCustomData konflikt, Collection<?> sitzberechnungEntities) {
//    return konflikt.getEntitaetenZurAuswahl().stream().anyMatch(sitzberechnungEntity -> sitzberechnungEntities.contains(sitzberechnungEntity));
//  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: Gibt ab, welche Stels oder Listen (hier: Stels) bei der Unterverteilung innerhalb der Gruppe wie viele Sitze durch Listenerschöpfung verloren haben
   */
  public Map<String, Integer> getVonListenerschoepfungBeiUnterverteilungBetroffeneStelsInGruppe(GruppePK gruppe) {
    return getZuteilungenStream(VerteilungTyp.UNTERVERTEILUNG, ZuteilungTyp.LISTENERSCHOEPFUNG)
            .filter(innerhalbVonGruppe(gruppe))
            .filter(zuteilung -> zuteilung.getSitze() != 0)
            .filter(zuteilung -> zuteilung.getVerteilungAn().isStel())
            .collect(Collectors.toMap(
                    zuteilung -> zuteilung.getVerteilungAn().getStelKey(),
                    zuteilung -> -zuteilung.getSitze()));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12: Gibt ab, welche Stels oder Listen (hier: Listen) bei der Unterverteilung innerhalb der Gruppe wie viele Sitze durch Listenerschöpfung verloren haben
   */
  public Map<WahlvorschlagPK, Integer> getVonListenerschoepfungBeiUnterverteilungBetroffeneListenInGruppe(Collection<WahlvorschlagPK> listenZurAuswahl, GruppePK gruppe) {
    return getZuteilungenStream(VerteilungTyp.UNTERVERTEILUNG, ZuteilungTyp.LISTENERSCHOEPFUNG)
            .filter(innerhalbVonGruppe(gruppe))
            .filter(zuteilung -> zuteilung.getSitze() != 0)
            .filter(zuteilung -> zuteilung.getVerteilungAn().isListe())
            .collect(Collectors.toMap(
                    zuteilung -> getListeMatching(listenZurAuswahl, zuteilung.getVerteilungAn()),
                    zuteilung -> -zuteilung.getSitze()));
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Anzahl Restsitze, die vor einer anschließenden d'Hondt-Verteilung noch unbesetzt waren.
   * <p>
   * "Hierna waren er nog ... restzetels te verdelen. Deze zetels zijn toegewezen aan de lijsten
   * die met een zetel erbij het grootste gemiddelde aantal stemmen per zetel hebben.
   * Hierbij heeft iedere lijst niet meer dan één zetel toegewezen gekregen", siehe OSV-1481
   */
  public int getAnzahlUnbesetzteRestsitzeVorUnterverteilungNachDHondtInGruppe(GruppePK gruppe) {
    return getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
            .mapToInt(DHondtSitzverteilung::getSitzeGesamtZuVerteilen)
            .findAny()
            .orElse(0);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Anzahl der "restzetel"-Spalten bei einer anschließenden d'Hondt-Verteilung, siehe OSV-1481
   */
  public int getAnzahlLaeufeUnterverteilungNachDHondtInGruppe(GruppePK gruppe) {
    return getAnzahlLaeufe(getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe));
  }

  private int getAnzahlLaeufe(Stream<DHondtSitzverteilung> stream) {
    return stream
            .flatMap(dHondtSitzverteilung -> dHondtSitzverteilung.getDHondtQuotienten().stream())
            .mapToInt(DHondtQuotient::getLauf)
            .max()
            .orElse(0);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Brüche in der Tabelle bei einer anschließenden d'Hondt-Verteilung, hier für Stels
   *
   * @param lauf 1-basierter Index der d'Hondt-Schritte bei der Unterverteilung, also zwischen 1 und getAnzahlVerteilungsschritteUnterverteilungNachDHondtInGruppe(gruppe)
   */
//  public Fraction getDHondtQuotientVonStelInUnterverteilungInGruppe(Stel stel, GruppePK gruppe, int lauf) {
//    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
//            .filter(anStel(stel));
//    DHondtQuotient dHondtZuteilung = getDHondtZuteilungInLauf(lauf, stream).orElse(null);
//    return getDHondtQuotient(dHondtZuteilung);
//  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Brüche in der Tabelle bei einer anschließenden d'Hondt-Verteilung, hier für Listen
   *
   * @param lauf 1-basierter Index der d'Hondt-Schritte bei der Unterverteilung, also zwischen 1 und getAnzahlVerteilungsschritteUnterverteilungNachDHondtInGruppe(gruppe)
   */
  public Fraction getDHondtQuotientVonListeInUnterverteilungInGruppe(WahlvorschlagPK liste, GruppePK gruppe, int lauf) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
            .filter(anListe(liste));
    DHondtQuotient dHondtZuteilung = getDHondtZuteilungInLauf(lauf, stream).orElse(null);
    return getDHondtQuotient(dHondtZuteilung);
  }

  private Fraction getDHondtQuotient(DHondtQuotient dHondtQuotient) {
    if (dHondtQuotient == null) {
      return null;
    }
    return new Fraction(dHondtQuotient.getZaehler(), dHondtQuotient.getNenner());
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Information, welcher Bruch zu einem Sitzgewinn geführt hat (Darstellung in Fettdruck), hier für Stels
   *
   * @param lauf 1-basierter Index der d'Hondt-Schritte bei der Oberverteilung, also zwischen 1 und getAnzahlVerteilungsschritteOberverteilungNachDHondt()
   */
//  public boolean isSitzgewinnNachDHondtFuerStelImLaufInUnterverteilungInGruppe(Stel stel, GruppePK gruppe, int lauf) {
//    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
//            .filter(anStel(stel));
//    return isSitzgewinnNachDHondtImLauf(lauf, stream);
//  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Information, welcher Bruch zu einem Sitzgewinn geführt hat (Darstellung in Fettdruck), hier für Listen
   *
   * @param lauf 1-basierter Index der d'Hondt-Schritte bei der Oberverteilung, also zwischen 1 und getAnzahlVerteilungsschritteOberverteilungNachDHondt()
   */
  public boolean isSitzgewinnNachDHondtFuerListeImLaufInUnterverteilungInGruppe(WahlvorschlagPK liste, GruppePK gruppe, int lauf) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
            .filter(anListe(liste));
    return isSitzgewinnNachDHondtImLauf(lauf, stream);
  }

  private boolean isSitzgewinnNachDHondtImLauf(int lauf, Stream<DHondtSitzverteilung> stream) {
    return getDHondtZuteilungInLauf(lauf, stream)
            .map(DHondtQuotient::getSitzAusRestanteil)
            .orElse(false);
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Spalte "aantal restzetels", hier für Stels
   */
//  public long getAnzahlRestsitzeNachDHondtFuerStelAusUnterverteilungInGruppe(Stel stel, GruppePK gruppe) {
//    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
//            .filter(anStel(stel));
//    return getAnzahlRestsitzeNachDHondt(stream);
//  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Spalte "aantal restzetels", hier für Listen
   */
  public long getAnzahlRestsitzeNachDHondtFuerListeAusUnterverteilungInGruppe(WahlvorschlagPK liste, GruppePK gruppe) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe)
            .filter(anListe(liste));
    return getAnzahlRestsitzeNachDHondt(stream);
  }

  private long getAnzahlRestsitzeNachDHondt(Stream<DHondtSitzverteilung> stream) {
    return stream
            .mapToLong(this::getAnzahlRestsitzeAusOberverteilungNachDHondt)
            .findAny()
            .orElse(0);
  }

  private long getAnzahlRestsitzeAusOberverteilungNachDHondt(DHondtSitzverteilung dHondtSitzverteilung) {
    return dHondtSitzverteilung.getDHondtQuotienten().stream().filter(DHondtQuotient::getSitzAusRestanteil).count();
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Untere Zeile "Restzetel toegekend aan lijst"
   * <p>
   * In jedem Lauf wird nur ein Sitz zugewiesen. Falls in einem Schritt bei der Verteilung mehrere Sitz zugleich
   * zugewiesen werden, so wird das in mehrere Läufe unterteilt, siehe OSV-1458, issue 4.
   *
   * @return wählt aus den gegebenen stels diejenige aus, die im gegebenen lauf einen Sitz gewonnen hat, falls es sich dabei um ein Stel handelt. null, falls es sich dabei um eine Liste handelt.
   */
//  public Stel getStelDHondtGewinnerUnterverteilungInGruppe(Collection<Stel> stels, GruppePK gruppe, int lauf) {
//    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe);
//    AllgemeineListe sitzgewinner = getDHondtGewinner(lauf, stream);
//    return getStelMatching(stels, sitzgewinner);
//  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Untere Zeile "Restzetel toegekend aan lijst"
   * <p>
   * In jedem Lauf wird nur ein Sitz zugewiesen. Falls in einem Schritt bei der Verteilung mehrere Sitz zugleich
   * zugewiesen werden, so wird das in mehrere Läufe unterteilt, siehe OSV-1458, issue 4.
   *
   * @return wählt aus den gegebenen stels diejenige aus, die im gegebenen lauf einen Sitz gewonnen hat, falls es sich dabei um eine Liste handelt. null, falls es sich dabei um einen Stel handelt.
   */
  public WahlvorschlagPK getListeDHondtGewinnerUnterverteilungInGruppe(Collection<WahlvorschlagPK> listen, GruppePK gruppe, int lauf) {
    Stream<DHondtSitzverteilung> stream = getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(gruppe);
    AllgemeineListe sitzgewinner = getDHondtGewinner(lauf, stream);
    return getListeMatching(listen, sitzgewinner);
  }

  private AllgemeineListe getDHondtGewinner(int lauf, Stream<DHondtSitzverteilung> stream) {
    return stream
            .filter(isSitzgewinnerInLauf(lauf))
            .findAny()
            .map(DHondtSitzverteilung::getVerteilungAn)
            .orElseThrow(() -> new IllegalStateException(
                    "Bei einer d'Hondt-Verteilung sollte immer genau ein Sitz pro Lauf zugewiesen werden."));
  }

  private Predicate<DHondtSitzverteilung> isSitzgewinnerInLauf(int lauf) {
    return dHondtSitzverteilung -> dHondtSitzverteilung.getDHondtQuotienten().stream()
            .anyMatch(dHondtZuteilung -> dHondtZuteilung.getLauf() == lauf && dHondtZuteilung.getSitzAusRestanteil());
  }

  /**
   * P22-1, Kap. 11 oder P22-2, Kap. 12, Losen bei Unterverterteilung nach d'Hondt
   * <p>
   * Da man dem Konflikt nicht ansieht., in welcher Unterverteilung (in welcher Gruppe) er aufgetreten ist, muss das an Hand der Teilnehmenden Stels und Listen ermittelt werden
   */
//  public List<OsvLegacyKonfliktCustomData> getKonflikteBeiUnterverteilungNachDHondtZwischenStelsUndListen(
//          Collection<Stel> alleStelsDerGruppe, Collection<WahlvorschlagPK> alleListenDerGruppe) {
//
//    return getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt.DHONDT_P2)
//            .filter(konflikt -> isKonfliktZwischen(konflikt, alleStelsDerGruppe, alleListenDerGruppe))
//            .collect(Collectors.toList());
//  }

  /**
   * P22-1 oder P22-2, Kap. 13: Besonderheiten bei der Nominierung der Gewählten
   */
  public List<BesonderheitBeiNominierungDerGewaehlten> getBesonderheiten() {
    return osvLegacyErgebnisDaten.getBesonderheiten();
  }

  /**
   * P22-1 oder P22-2, Kap. 13: Information, ob ein gewählter Kandidat
   * im Kapitel "I. Met voorkeur gekozen kandidaten"
   * oder im Kapitel "II. Overige gekozen kandidaten" aufgeführt wird
   */
  public boolean isMitVorzugsstimmenGewaehlt(PersonendatenPK kandidatur) {
    return osvLegacyErgebnisDaten.getMitVorzugGewaehlteKandidaturen().stream()
            .anyMatch(mitVorzugGewaehlteKandidatur -> kandidatur.toString().equals(mitVorzugGewaehlteKandidatur.getKandidaturKey()));
  }

  /**
   * P22-1 oder P22-2, Kap. 13: "De volgende kandidaten zijn met voorkeurstemmen gekozen. Deze kandidaten hebben [meer dan | ten minste of gelijk aan] ... % van de kiesdeler gehaald"
   */
  public long getVorzugsschwelleInProzent() {
    return osvLegacyErgebnisDaten.getVorzugsschwelleInProzent();
  }

  /**
   * P22-1 oder P22-2, Kap. 13: Gibt an, welches von [meer dan | ten minste of gelijk aan] zutrifft
   *
   * @return true, wenn die Vorzugsschwelle für einen Vorzugssitz übertroffen werden muss, false, wenn es ausreicht, sie
   * zu erreichen.
   */
  public boolean getMussVorzugsschwelleUebertreffen() {
    return osvLegacyErgebnisDaten.getMussVorzugsschwelleUebertreffen();
  }

  /**
   * P22-1 oder P22-2, Kap. 13, Losen beim Bestimmen der gewählten Vorzugskandidaten
   * <p>
   * Da man am Konflikt nicht erkennt, zu welcher Gruppe er erhört, muss man alle gewählten Kandidaturen übergeben, damit die Zuordnung möglich ist.
   */
//  public List<OsvLegacyKonfliktCustomData> getKonflikteBeiKandidaten(Collection<PersonendatenPK> alleGewaehltenKandidaturenDerGruppe) {
//    return getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt.CANDIDATES)
//            .filter(konflikt -> isKonfliktZwischen(konflikt, alleGewaehltenKandidaturenDerGruppe))
//            .collect(Collectors.toList());
//  }


  public Boolean isMitGeaenderterReihenfolge(WahlvorschlagPK wahlvorschlagPK) {
    return osvLegacyErgebnisDaten
            .getMitGeaenderterReihenfolgeListen().stream()
            .anyMatch(liste -> isGleicheListe(wahlvorschlagPK, liste));
  }

  public Boolean isMitGeaenderterReihenfolge(String stelId) {
    return osvLegacyErgebnisDaten
            .getMitGeaenderterReihenfolgeListen().stream()
            .anyMatch(stel -> isGleicherStel(stelId, stel));
  }


  /********* Allgemeine private Hilfsmethoden ********/

  private Stream<Zuteilung> getZuteilungenStream(VerteilungTyp verteilungTyp, ZuteilungTyp ersteZuteilung) {
    return osvLegacyErgebnisDaten.getZuteilungen().stream()
            .filter(byZuteilungTyp(ersteZuteilung))
            .filter(byVerteilungTyp(verteilungTyp));
  }

  private Stream<OsvLegacyKonfliktCustomData> getKonflikteVomTypStream(OsvLegacyErgebnisKonfliktArt typ) {
    return konflikte.stream()
            .filter(konflikt -> konflikt.getOsvLegacyErgebnisKonfliktArt().equals(typ));
  }

  private GruppePK getGruppeMatching(Collection<GruppePK> gruppenZurAuswahl, AllgemeineListe allgemeineListe) {
    return gruppenZurAuswahl.stream()
            .filter(gruppe -> isGleicheGruppe(gruppe, allgemeineListe))
            .findAny()
            .orElse(null);
  }

//  private Stel getStelMatching(Collection<Stel> stelsZurAuswahl, AllgemeineListe allgemeineListe) {
//    return stelsZurAuswahl.stream()
//            .filter(stel -> isGleicherStel(stel, allgemeineListe))
//            .findAny()
//            .orElse(null);
//  }

  private WahlvorschlagPK getListeMatching(Collection<WahlvorschlagPK> listenZurAuswahl, AllgemeineListe allgemeineListe) {
    return listenZurAuswahl.stream()
            .filter(liste -> isGleicheListe(liste, allgemeineListe))
            .findAny()
            .orElse(null);
  }

  private GruppePK getGruppeMitKey(Collection<GruppePK> gruppenZurAuswahl, String gruppeKey) {
    return gruppenZurAuswahl.stream()
            .filter(gruppe -> isGruppeMitKey(gruppe, gruppeKey))
            .findAny()
            .orElse(null);
  }

//  private Stel getStelMitKey(Collection<Stel> stelsZurAuswahl, String stelKey) {
//    return stelsZurAuswahl.stream()
//            .filter(stel -> isStelMitKey(stel, stelKey))
//            .findAny()
//            .orElse(null);
//  }

  private WahlvorschlagPK getListeMitKey(Collection<WahlvorschlagPK> listesZurAuswahl, String listeKey) {
    return listesZurAuswahl.stream()
            .filter(liste -> isListeMitKey(liste, listeKey))
            .findAny()
            .orElse(null);
  }

  private Optional<DHondtQuotient> getDHondtZuteilungInLauf(int lauf, Stream<DHondtSitzverteilung> stream) {
    return stream
            .flatMap(dHondtSitzverteilung -> dHondtSitzverteilung.getDHondtQuotienten().stream())
            .filter(dHondtZuteilung -> dHondtZuteilung.getLauf() == lauf)
            .findAny();
  }

  private Stream<DHondtSitzverteilung> getDHondtSitzverteilungenBeiOberverteilungStream() {
    return osvLegacyErgebnisDaten.getDHondtSitzverteilungen().stream()
            .filter(dHondtSitzverteilung -> dHondtSitzverteilung.getVerteilungTyp().equals(VerteilungTyp.OBERVERTEILUNG));
  }

  private Stream<DHondtSitzverteilung> getDHondtSitzverteilungenBeiUnterverteilungInGruppeStream(GruppePK gruppe) {
    return osvLegacyErgebnisDaten.getDHondtSitzverteilungen().stream()
            .filter(byVerteilungTyp(VerteilungTyp.UNTERVERTEILUNG))
            .filter(innerhalbVonGruppe(gruppe));
  }

  private Predicate<ZuteilungInVerteilung> byVerteilungTyp(VerteilungTyp verteilungTyp) {
    return zuteilung -> zuteilung.getVerteilungTyp().equals(verteilungTyp);
  }

  private Predicate<Zuteilung> byZuteilungTyp(ZuteilungTyp zuteilungTyp) {
    return zuteilung -> zuteilung.getZuteilungTyp().equals(zuteilungTyp);
  }

  private Predicate<ZuteilungInVerteilung> anGruppe(GruppePK gruppe) {
    return zuteilung -> isGleicheGruppe(gruppe, zuteilung.getVerteilungAn());
  }

  private Predicate<ZuteilungInVerteilung> anStel(String stelId) {
    return zuteilung -> isGleicherStel(stelId, zuteilung.getVerteilungAn());
  }

  private Predicate<ZuteilungInVerteilung> anListe(WahlvorschlagPK liste) {
    return zuteilung -> isGleicheListe(liste, zuteilung.getVerteilungAn());
  }

  private Predicate<ZuteilungInVerteilung> innerhalbVonGruppe(GruppePK gruppe) {
    return zuteilung -> isGleicheGruppe(gruppe, zuteilung.getVerteilungInnerhalbVon());
  }

  private boolean isGleicheGruppe(GruppePK gruppe, AllgemeineListe allgemeineListe) {
    return isGruppeMitKey(gruppe, allgemeineListe.getGruppeKey());
  }

  private boolean isGleicherStel(String stelId, AllgemeineListe allgemeineListe) {
    return Objects.equals(stelId, allgemeineListe.getStelKey());
  }

  private boolean isGleicheListe(WahlvorschlagPK liste, AllgemeineListe allgemeineListe) {
    return isListeMitKey(liste, allgemeineListe.getListeKey());
  }

  private boolean isGruppeMitKey(GruppePK gruppe, String gruppeKey) {
    return gruppe.toString().equals(gruppeKey);
  }

//  private boolean isStelMitKey(Stel stel, String stelKey) {
//    return stel.getKey().equals(stelKey);
//  }

  private boolean isListeMitKey(WahlvorschlagPK liste, String listeKey) {
    return liste.toString().equals(listeKey);
  }
}