
package de.ivu.elect.dokumente.ergebnis;

import static de.ivu.elect.jee.entity.EntityUtil.castTo;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySortedMap;
import static java.util.stream.Collectors.summarizingLong;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
import static org.apache.commons.lang3.StringUtils.firstNonBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

import javax.annotation.Nullable;

import de.ivu.document.generator.template.annotations.Document;
import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentMethod;
import de.ivu.document.generator.template.annotations.DocumentParam;
import de.ivu.document.generator.template.annotations.DocumentQueue;
import de.ivu.document.generator.template.annotations.DocumentRepeat;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.control.NlErgebnisDaten;
import de.ivu.elect.business.ergebnis.control.NlErgebnisDatenGueltige;
import de.ivu.elect.business.ergebnis.control.NlErgebnisDatenStimmzettel;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.gebietsbaum.control.GebietByPositionComparator;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsgruppierung;
import de.ivu.elect.business.gebietsbaum.entity.NlGebietsgruppierungArt;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppePK;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.internet.control.GebietUndStimmabgabeart;
import de.ivu.elect.business.kandidatur.entity.Ersatzkandidatur;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.kandidatur.entity.NlListenkandidatur;
import de.ivu.elect.business.person.entity.PersonendatenPK;
import de.ivu.elect.business.sitzberechnung.entity.OsvLegacyArtikelnummer;
import de.ivu.elect.business.sitzberechnung.entity.OsvLegacyKonfliktCustomData;
import de.ivu.elect.business.stimmeingabe.boundary.NlVoteType;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahl.entity.NlWahlCustomData;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.Listenverbindung;
import de.ivu.elect.dokumente.AnschriftDokument;
import de.ivu.elect.dokumente.WasElectContext;
import de.ivu.elect.dokumente.ergebnis.p22.P22ErgebnisDatenCustomDataDocument;
import de.ivu.elect.dokumente.gebiet.BasicGebietDokument;
import de.ivu.elect.dokumente.gebiet.NlGebietDokument;
import de.ivu.elect.dokumente.kandidatur.CoreKandidaturDokument;
import de.ivu.elect.dokumente.kandidatur.KandidaturCoreDaten;
import de.ivu.elect.dokumente.kandidatur.KandidaturDokument;
import de.ivu.elect.dokumente.wahl.NlCoreWahlCustomDataDocument;
import de.ivu.elect.dokumente.wahlvorschlag.CoreWahlvorschlagsdatenDocument;
import de.ivu.elect.dokumente.wahlvorschlag.GruppeDokument;
import de.ivu.elect.dokumente.wahlvorschlag.WahlvorschlagCoreDaten;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis.GebietMitListenDocument;
import de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis.GebietMitStimmenDocument;
import de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis.KandidaturMitStimmergebnissenDocument;
import de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis.ListeMitStimmergebnissenDocument;
import de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis.WasListenverbindungDokument;
import de.ivu.elect.was.exchange.diff.EmlErgebnisDifferenz;
import de.ivu.elect.was.exchange.ergebnis.eml.Eml510bGSBErgebnisExportMapper;
import de.ivu.elect.was.exchange.ergebnis.eml.Eml510bHSBErgebnisExportMapper;
import de.ivu.elect.was.exchange.ergebnis.eml.Eml510cCSBErgebnisExportMapper;
import de.ivu.elect.was.exchange.ergebnis.eml.Eml510cHSBErgebnisExportMapper;
import de.ivu.elect.was.exchange.ergebnis.eml.Eml510dCSBErgebnisExportMapper;
import de.ivu.elect.was.exchange.ergebnis.eml.Eml520ErgebnisExportMapper;

/**
 * Siehe auch <a href="https://support.elect-it.com/ticket/browse/ELECT-15243">ELECT-15243</a>
 */
@Document(NlErgebnisDatenCustomDataDocument.DOKUMENT_PREFIX) // ELECT-9708
public class NlErgebnisDatenCustomDataDocument extends ErgebnisDatenCustomDataDocument {

  private static final long serialVersionUID = 1L;

  private static final FileFormat FILE_FORMAT_EML_UNBEKANNT = NlCoreWahlCustomDataDocument.FILE_FORMAT_UNBEKANNT;

  public static final String DOKUMENT_PREFIX = "nl-ergebnis-daten-custom";

  @DocumentSimpleField("IstZentraleErfassung")
  public final boolean zentraleErfassung; // ELECTVAPP-2167

  @DocumentSimpleField("Datum-Aktuell")
  public final Date datumAktuell;

  @DocumentSimpleField("Datum-Aktuell-Formatted-DDMMYYYY")
  public final String datumAktuellFormattedDDMMYYYY;

  @DocumentSimpleField("Datum-Aktuell-Formatted-Footer")
  public final String datumAktuellFormattedFooter;

  @DocumentComplexField("Wahlgebiet")
  public final BasicGebietDokument wahlgebiet;

  @DocumentSimpleField("Wahlgebiet-Gebietsart-Name")
  public final String wahlgebietGebietsartName; // ELECT-14227

  @DocumentSimpleField("Gebiet-CSB-Name")
  public final String gebietCSBName;

  @DocumentSimpleField("Wahlbehoerde-Wahlleiter-Name")
  public final String wahlbehoerdeWahlleiterName;

  @DocumentComplexField("Wahlbehoerde-Anschrift")
  public final AnschriftDokument wahlbehoerdeAnschrift;

  @DocumentComplexField("Wahlbehoerde-Dokument-Erstellt-Anschrift")
  public final AnschriftDokument wahlbehoerdeDokumentErstelltAnschrift;

  @DocumentSimpleField("Wahlbehoerde-Dokument-Erstellt-Am")
  public final Date wahlbehoerdeDokumentErstelltAm;

  @DocumentSimpleField("Wahlbehoerde-Dokument-Erstellt-Am-Formatted-DDMMYYYY")
  public final String wahlbehoerdeDokumentErstelltAmFormattedDDMMYYYY;

  @DocumentSimpleField("Wahlbehoerde-Dokument-Erstellt-Am-Formatted-Footer")
  public final String wahlbehoerdeDokumentErstelltAmFormattedFooter;

  @DocumentComplexField("Gewaehltes-Gremium")
  public final String gewaehltesGremium;

  @DocumentComplexField("Gewaehltes-Gremium-Von")
  public final String gewaehltesGremiumVon; // ELECT-14237

  @DocumentComplexField("Gewaehltes-Gremium-Von-Wahlgebiet")
  public final String gewaehltesGremiumVonWahlgebiet; // ELECT-14237

  @DocumentComplexField("Gewaehltes-Gremium-Durchfuehrendes-Organ")
  public final String gewaehltesGremiumDurchfuehrendesOrgan;

  @DocumentComplexField("Gewaehltes-Gremium-Anschrift")
  public final AnschriftDokument gewaehltesGremiumAnschrift;

  @DocumentSimpleField("Wahlausschusssitzung-Zuvor-Beginn")
  public final Date wahlausschusssitzungZuvorBeginn; // ELECT-15281

  @DocumentSimpleField("Wahlausschusssitzung-Zuvor-Beginn-Formatted-Datum")
  public final String wahlausschusssitzungZuvorBeginnFormattedDatum;

  @DocumentSimpleField("Wahlausschusssitzung-Zuvor-Beginn-Formatted-Zeit")
  public final String wahlausschusssitzungZuvorBeginnFormattedZeit;

  @DocumentComplexField("Wahlausschusssitzung-Anschrift")
  public final AnschriftDokument wahlausschusssitzungAnschrift;

  @DocumentSimpleField("Wahlausschusssitzung-Beginn")
  public final Date wahlausschusssitzungBeginn;

  @DocumentSimpleField("Wahlausschusssitzung-Beginn-Formatted-Datum")
  public final String wahlausschusssitzungBeginnFormattedDatum;

  @DocumentSimpleField("Wahlausschusssitzung-Beginn-Formatted-Zeit")
  public final String wahlausschusssitzungBeginnFormattedZeit;

  @DocumentSimpleField("Wahlausschusssitzung-Ende")
  public final Date wahlausschusssitzungEnde;

  @DocumentSimpleField("Wahlausschusssitzung-Ende-Formatted-Datum")
  public final String wahlausschusssitzungEndeFormattedDatum;

  @DocumentSimpleField("Wahlausschusssitzung-Ende-Formatted-Zeit")
  public final String wahlausschusssitzungEndeFormattedZeit;

  @DocumentSimpleField("Wahlausschusssitzung-Beginn-Ueberseegebiete")
  public final Date wahlausschusssitzungBeginnUeberseegebiete;

  @DocumentSimpleField("Wahlausschusssitzung-Beginn-Ueberseegebiete-Formatted-Datum")
  public final String wahlausschusssitzungBeginnUeberseegebieteFormattedDatum;

  @DocumentSimpleField("Wahlausschusssitzung-Beginn-Ueberseegebiete-Formatted-Zeit")
  public final String wahlausschusssitzungBeginnUeberseegebieteFormattedZeit;

  @DocumentSimpleField("Wahlausschusssitzung-Ende-Ueberseegebiete")
  public final Date wahlausschusssitzungEndeUeberseegebiete;

  @DocumentSimpleField("Wahlausschusssitzung-Ende-Ueberseegebiete-Formatted-Datum")
  public final String wahlausschusssitzungEndeUeberseegebieteFormattedDatum;

  @DocumentSimpleField("Wahlausschusssitzung-Ende-Ueberseegebiete-Formatted-Zeit")
  public final String wahlausschusssitzungEndeUeberseegebieteFormattedZeit;

  @DocumentSimpleField("Wahlausschusssitzung-Fehler-Vermutet")
  public final String wahlausschusssitzungFehlerVermutet;

  @DocumentQueue(value = "Wahlausschusssitzung-Fehler-Vermutet-Zeilen", elementClass = String.class)
  public final LinkedList<String> wahlausschusssitzungFehlerVermutetZeilen;

  @DocumentSimpleField("Wahlausschusssitzung-Einwaende")
  public final String wahlausschusssitzungEinwaende;

  @DocumentQueue(value = "Wahlausschusssitzung-Einwaende-Zeilen", elementClass = String.class)
  public final LinkedList<String> wahlausschusssitzungEinwaendeZeilen;

  @DocumentSimpleField("Wahlausschusssitzung-Einwaende-Bemerkungen")
  public final String wahlausschusssitzungBemerkungen;

  @DocumentQueue(value = "Wahlausschusssitzung-Einwaende-Bemerkungen-Zeilen", elementClass = String.class)
  public final LinkedList<String> wahlausschusssitzungBemerkungenZeilen;

  @DocumentSimpleField("Einwohnerzahl-Veroeffentlichung-ID")
  public final String einwohnerzahlVeroeffentlichungId;

  @DocumentSimpleField("Einwohnerzahl-Veroeffentlichung-Datum")
  public final Date einwohnerzahlVeroeffentlichungDatum;

  @DocumentSimpleField("Einwohnerzahl-Veroeffentlichung-Datum-Formatted-DDMMYYYY")
  public final String einwohnerzahlVeroeffentlichungDatumFormattedDDMMYYYY;

  @DocumentSimpleField("Einwohnerzahl-Veroeffentlichung-Datum-Formatted-YYYY")
  public final String einwohnerzahlVeroeffentlichungDatumFormattedYYYY;

  @DocumentComplexField("p22Daten")
  public final P22ErgebnisDatenCustomDataDocument p22Daten;

  @DocumentRepeat(value = "VoteValueGebiete", elementClass = NlGebietDokument.class, itemName = "voteValueGebiet")
  public final List<NlGebietDokument> voteValueGebiete; // ELECT-13505

  @DocumentRepeat(value = "ErfassungsgebieteMitListen", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebieteMitListen;

  @DocumentRepeat(value = "ErfassungsgebieteMitListenNurUrnenwahl", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebieteMitListenNurUrnenwahl; // ELECT-11694

  @DocumentRepeat(value = "ErfassungsgebieteMitListenNurBriefwahlGemeinde", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebieteMitListenNurBriefwahlGemeinde; // ELECT-11694

  @DocumentRepeat(value = "ErfassungsgebieteMitListenNurBriefwahlAusland", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebieteMitListenNurBriefwahlAusland; // ELECT-11694

  @DocumentRepeat(value = "ErfassungsgebietePruefungErforderlichFehlerInNiederschriftVermutet", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebietePruefungErforderlichFehlerInNiederschriftVermutet; // ELECT-16526

  @DocumentRepeat(value = "ErfassungsgebietePruefungErforderlichStimmzettelEingenommenAbweichend", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebietePruefungErforderlichStimmzettelEingenommenAbweichend; // ELECT-15560

  @DocumentRepeat(value = "ErfassungsgebieteNachPruefungKorrigiertStimmzettelEingenommenAbweichend", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebieteNachPruefungKorrigiertStimmzettelEingenommenAbweichend; // ELECT-15560

  @DocumentRepeat(value = "ErfassungsgebieteMitSonstigemFehlerNachPruefungKorrigiert", elementClass = GebietMitListenDocument.class, itemName = "erfassungsgebietMitListen")
  public final List<GebietMitListenDocument> erfassungsgebieteNachPruefungKorrigiertSonstigerFehler; // ELECT-15560

  @DocumentRepeat(value = "ListenSortiertNachRang ", elementClass = ListeMitStimmergebnissenDocument.class, itemName = "liste")
  public final List<ListeMitStimmergebnissenDocument> listenMitStimmergebnissenNachRang;

  @DocumentRepeat(value = "NlErgebnisKonflikte", elementClass = NlErgebnisKonfliktDocument.class, itemName = "konflikt")
  public final List<NlErgebnisKonfliktDocument> nlErgebnisKonflikte;

  @DocumentRepeat(value = "Gruppen-Nach-Relativ-Position", elementClass = GruppeDokument.class, itemName = "gruppe")
  public final List<GruppeDokument> gruppenSortiertNachPosition;

  @DocumentComplexField(value = "ListenstimmenProGruppe")
  public final ListenstimmenProGruppeTabelleDocument listenstimmenProGruppeTabelleDocument;

  private final NlErgebnisDatenCustomDataDocumentContext context;

  private final NlCoreWahlCustomDataDocument wahlCustomDataDocument;

  private final Map<GruppePK, List<KandidaturDokument>> kandidaturOhneWahlvorschlagDokumentePerGruppe; // ELECT-10559

  private final Map<PersonendatenPK, KandidaturDokument> kandidaturBevollmaechtigterDokumentPerKandidatur; // ELECT-11942

  private final EmlErgebnisDifferenz emlErgebnisDifferenz;

  public NlErgebnisDatenCustomDataDocument(WasElectContext wasElectContext, ErgebnisDaten ergebnisDaten, WahlvorschlagCoreDaten wahlvorschlagCoreDaten,
      List<Wahldurchfuehrungsgebiet> auswertungsgebiete, Stimmabgabeart stimmabgabeart, @Nullable EmlErgebnisDifferenz emlErgebnisDifferenz) {
    super(wasElectContext, ergebnisDaten, auswertungsgebiete, stimmabgabeart);

    this.zentraleErfassung = wasElectContext.getWahl().getCustomData(NlWahlCustomData.class).isZentraleErfassung(); // ELECTVAPP-2167

    this.emlErgebnisDifferenz = emlErgebnisDifferenz;

    Collection<Gruppe> gruppenInWahl = ergebnisDaten.getGruppen();

    this.context = new NlErgebnisDatenCustomDataDocumentContext(wasElectContext, ergebnisDaten, stimmabgabeart);

    this.wahlCustomDataDocument = new NlCoreWahlCustomDataDocument(wasElectContext, ergebnisDaten.getEntityAufStimmzettelDaten(), () -> gruppenInWahl,
        () -> new ArrayList<>(ergebnisDaten.getGebiete()), ergebnisDaten::getWahlvorschlaege);

    this.wahlgebiet = this.wahlCustomDataDocument.wahlgebiet;
    this.wahlgebietGebietsartName = this.wahlCustomDataDocument.wahlgebietGebietsartName;

    /*
     * Neue Felder ggf. auch in NlWusWahlgebietOderWurzelgebietCustomDataDocument ergänzen!
     */

    this.datumAktuell = this.wahlCustomDataDocument.datumAktuell;
    this.datumAktuellFormattedDDMMYYYY = this.wahlCustomDataDocument.datumAktuellFormattedDDMMYYYY;
    this.datumAktuellFormattedFooter = this.wahlCustomDataDocument.datumAktuellFormattedFooter;

    this.gebietCSBName = this.wahlCustomDataDocument.gebietCSBName;

    this.wahlbehoerdeWahlleiterName = this.wahlCustomDataDocument.wahlbehoerdeWahlleiterName;
    this.wahlbehoerdeAnschrift = this.wahlCustomDataDocument.wahlbehoerdeAnschrift;

    this.wahlbehoerdeDokumentErstelltAnschrift = this.wahlCustomDataDocument.wahlbehoerdeDokumentErstelltAnschrift;
    this.wahlbehoerdeDokumentErstelltAm = this.wahlCustomDataDocument.wahlbehoerdeDokumentErstelltAm;
    this.wahlbehoerdeDokumentErstelltAmFormattedDDMMYYYY = this.wahlCustomDataDocument.wahlbehoerdeDokumentErstelltAmFormattedDDMMYYYY;
    this.wahlbehoerdeDokumentErstelltAmFormattedFooter = this.wahlCustomDataDocument.wahlbehoerdeDokumentErstelltAmFormattedFooter;

    this.gewaehltesGremium = this.wahlCustomDataDocument.gewaehltesGremium;
    this.gewaehltesGremiumVon = this.wahlCustomDataDocument.gewaehltesGremiumVon;
    this.gewaehltesGremiumVonWahlgebiet = this.wahlCustomDataDocument.gewaehltesGremiumVonWahlgebiet;
    this.gewaehltesGremiumDurchfuehrendesOrgan = this.wahlCustomDataDocument.gewaehltesGremiumDurchfuehrendesOrgan;
    this.gewaehltesGremiumAnschrift = this.wahlCustomDataDocument.gewaehltesGremiumAnschrift;

    this.wahlausschusssitzungZuvorBeginn = this.wahlCustomDataDocument.wahlausschusssitzungZuvorBeginn;
    this.wahlausschusssitzungZuvorBeginnFormattedDatum = this.wahlCustomDataDocument.wahlausschusssitzungZuvorBeginnFormattedDatum;
    this.wahlausschusssitzungZuvorBeginnFormattedZeit = this.wahlCustomDataDocument.wahlausschusssitzungZuvorBeginnFormattedZeit;

    this.wahlausschusssitzungAnschrift = this.wahlCustomDataDocument.wahlausschusssitzungAnschrift;

    this.wahlausschusssitzungBeginn = this.wahlCustomDataDocument.wahlausschusssitzungBeginn;
    this.wahlausschusssitzungBeginnFormattedDatum = this.wahlCustomDataDocument.wahlausschusssitzungBeginnFormattedDatum;
    this.wahlausschusssitzungBeginnFormattedZeit = this.wahlCustomDataDocument.wahlausschusssitzungBeginnFormattedZeit;

    this.wahlausschusssitzungEnde = this.wahlCustomDataDocument.wahlausschusssitzungEnde;
    this.wahlausschusssitzungEndeFormattedDatum = this.wahlCustomDataDocument.wahlausschusssitzungEndeFormattedDatum;
    this.wahlausschusssitzungEndeFormattedZeit = this.wahlCustomDataDocument.wahlausschusssitzungEndeFormattedZeit;

    this.wahlausschusssitzungBeginnUeberseegebiete = this.wahlCustomDataDocument.wahlausschusssitzungBeginnUeberseegebiete;
    this.wahlausschusssitzungBeginnUeberseegebieteFormattedDatum = this.wahlCustomDataDocument.wahlausschusssitzungBeginnUeberseegebieteFormattedDatum;
    this.wahlausschusssitzungBeginnUeberseegebieteFormattedZeit = this.wahlCustomDataDocument.wahlausschusssitzungBeginnUeberseegebieteFormattedZeit;

    this.wahlausschusssitzungEndeUeberseegebiete = this.wahlCustomDataDocument.wahlausschusssitzungEndeUeberseegebiete;
    this.wahlausschusssitzungEndeUeberseegebieteFormattedDatum = this.wahlCustomDataDocument.wahlausschusssitzungEndeUeberseegebieteFormattedDatum;
    this.wahlausschusssitzungEndeUeberseegebieteFormattedZeit = this.wahlCustomDataDocument.wahlausschusssitzungEndeUeberseegebieteFormattedZeit;

    this.wahlausschusssitzungFehlerVermutet = this.wahlCustomDataDocument.wahlausschusssitzungFehlerVermutet;
    this.wahlausschusssitzungFehlerVermutetZeilen = this.wahlCustomDataDocument.wahlausschusssitzungFehlerVermutetZeilen;

    this.wahlausschusssitzungEinwaende = this.wahlCustomDataDocument.wahlausschusssitzungEinwaende;
    this.wahlausschusssitzungEinwaendeZeilen = this.wahlCustomDataDocument.wahlausschusssitzungEinwaendeZeilen;

    this.wahlausschusssitzungBemerkungen = this.wahlCustomDataDocument.wahlausschusssitzungBemerkungen;
    this.wahlausschusssitzungBemerkungenZeilen = this.wahlCustomDataDocument.wahlausschusssitzungBemerkungenZeilen;

    this.einwohnerzahlVeroeffentlichungId = this.wahlCustomDataDocument.einwohnerzahlVeroeffentlichungId;
    this.einwohnerzahlVeroeffentlichungDatum = this.wahlCustomDataDocument.einwohnerzahlVeroeffentlichungDatum;
    this.einwohnerzahlVeroeffentlichungDatumFormattedDDMMYYYY = this.wahlCustomDataDocument.einwohnerzahlVeroeffentlichungDatumFormattedDDMMYYYY;
    this.einwohnerzahlVeroeffentlichungDatumFormattedYYYY = this.wahlCustomDataDocument.einwohnerzahlVeroeffentlichungDatumFormattedYYYY;

    Map<Liste, ListeMitStimmergebnissenDocument> ergebnisDokumentPerListe = new HashMap<>();
    Map<Kandidatur, KandidaturMitStimmergebnissenDocument> ergebnisDokumentPerKandidatur = new HashMap<>();

    this.voteValueGebiete = this.context.getVoteValueGebiete().stream().map(voteValueGebiet -> new NlGebietDokument(wasElectContext, voteValueGebiet)).collect(toList());

    this.erfassungsgebieteMitListen = createErfassungsgebieteMitListenDocuments(wasElectContext, ergebnisDaten, auswertungsgebiete, ergebnisDokumentPerListe, ergebnisDokumentPerKandidatur);
    this.erfassungsgebieteMitListenNurUrnenwahl = filterErfassungsgebiete(this.erfassungsgebieteMitListen, NlErgebnisDaten.ERFASSUNGSGEBIET_URNENWAHL_GEMEINDE);
    this.erfassungsgebieteMitListenNurBriefwahlGemeinde = filterErfassungsgebiete(this.erfassungsgebieteMitListen, NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_GEMEINDE);
    this.erfassungsgebieteMitListenNurBriefwahlAusland = filterErfassungsgebiete(this.erfassungsgebieteMitListen, NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_AUSLAND);

    // ELECT-15560
    Map<String, NlGebietsgruppierungArt> artPerArtName = NlGebietsgruppierungArt.ARTEN_KORREKTUREN_ERFASSUNGSGEBIETE.stream().collect(toMap(NlGebietsgruppierungArt::getArt, Function.identity()));
    Map<NlGebietsgruppierungArt, List<Gebiet>> erfassungsgebietePerArt = new HashMap<>();

    for (Gebietsgruppierung gebietsgruppierung : ergebnisDaten.getGebietsgruppierungen()) {
      NlGebietsgruppierungArt art = artPerArtName.get(gebietsgruppierung.getGebietsgruppierungArt());

      if (art != null) {
        erfassungsgebietePerArt.computeIfAbsent(art, ignored -> new ArrayList<>()).addAll(gebietsgruppierung.getGebiete());
      }
    }

    this.erfassungsgebietePruefungErforderlichFehlerInNiederschriftVermutet = filterErfassungsgebiete(this.erfassungsgebieteMitListen,
        gebiet -> erfassungsgebietePerArt.getOrDefault(NlGebietsgruppierungArt.ERFASSUNGSGEBIET_PRUEFUNG_ERFORDERLICH_FEHLER_IN_NIEDERSCHRIFT_VERMUTET, emptyList()).contains(gebiet));
    this.erfassungsgebietePruefungErforderlichStimmzettelEingenommenAbweichend = filterErfassungsgebiete(this.erfassungsgebieteMitListen,
        gebiet -> erfassungsgebietePerArt.getOrDefault(NlGebietsgruppierungArt.ERFASSUNGSGEBIET_PRUEFUNG_ERFORDERLICH_STIMMZETTEL_EINGENOMMEN_ABWEICHEND, emptyList()).contains(gebiet));
    this.erfassungsgebieteNachPruefungKorrigiertStimmzettelEingenommenAbweichend = filterErfassungsgebiete(this.erfassungsgebieteMitListen,
        gebiet -> erfassungsgebietePerArt.getOrDefault(NlGebietsgruppierungArt.ERFASSUNGSGEBIET_NACH_PRUEFUNG_KORRIGERT_STIMMZETTEL_EINGENOMMEN_ABWEICHEND, emptyList()).contains(gebiet));
    this.erfassungsgebieteNachPruefungKorrigiertSonstigerFehler = filterErfassungsgebiete(this.erfassungsgebieteMitListen,
        gebiet -> erfassungsgebietePerArt.getOrDefault(NlGebietsgruppierungArt.ERFASSUNGSGEBIET_NACH_PRUEFUNG_KORRIGERT, emptyList()).contains(gebiet));

    this.gruppenSortiertNachPosition = this.context.getPolitischeGruppenSortedByPosition().stream().map(GruppeDokument::new).collect(toCollection(LinkedList::new));

    if (ergebnisDaten.getSitzberechnungsalgorithmus().isBerechnetErgebnis()
        /* ELECT-10263 */ && wasElectContext.getWahl().getCustomData(NlWahlCustomData.class).getNlWahlPhase().isFreigabe() /* ELECT-10453 */) {
      this.p22Daten = new P22ErgebnisDatenCustomDataDocument(this.context, this.wahlCustomDataDocument);
    } else {
      this.p22Daten = P22ErgebnisDatenCustomDataDocument.EMPTY_OBJECT;
    }

    this.listenstimmenProGruppeTabelleDocument = new ListenstimmenProGruppeTabelleDocument(this.context);

    this.nlErgebnisKonflikte = createErgebnisKonflikteDocuments(ergebnisDaten, ergebnisDokumentPerListe, ergebnisDokumentPerKandidatur, wasElectContext.getMessages());

    this.listenMitStimmergebnissenNachRang = ergebnisDokumentPerListe.values().stream() //
        .sorted((one, another) -> Long.compare(another.anzahlGueltigerStimmen, one.anzahlGueltigerStimmen)) //
        .collect(toList());

    this.kandidaturOhneWahlvorschlagDokumentePerGruppe = new HashMap<>();

    this.kandidaturBevollmaechtigterDokumentPerKandidatur = new HashMap<>();

    for (Gruppe gruppe : gruppenInWahl) {
      if (gruppe.isPolitischeGruppe()) {
        List<KandidaturDokument> kandidaturOhneWahlvorschlagDokumente = new ArrayList<>();

        Set<Listenkandidatur> listenkandidaturenAufListenBetrachtet = new HashSet<>();
        Set<Listenkandidatur> listenkandidaturenAufListen = ergebnisDaten.getListenDerGruppe(gruppe).stream() //
            .flatMap(liste -> liste.getListenkandidaturen().stream()) //
            .collect(toSet());

        for (Listenkandidatur listenkandidatur : listenkandidaturenAufListen) {
          if (!listenkandidaturenAufListenBetrachtet.contains(listenkandidatur)) {
            kandidaturOhneWahlvorschlagDokumente.add(this.wahlCustomDataDocument.createKandidaturOhneWahlvorschlagDokument(wasElectContext, wahlvorschlagCoreDaten, listenkandidatur));

            listenkandidaturenAufListenBetrachtet.add(listenkandidatur);
            listenkandidaturenAufListenBetrachtet.addAll(listenkandidatur.getIdentischVerknuepfteListenkandidaturen()); // ELECT-10795
          }
        }

        this.kandidaturOhneWahlvorschlagDokumentePerGruppe.put(gruppe.getPk(), kandidaturOhneWahlvorschlagDokumente);

        for (Listenkandidatur listenkandidatur : listenkandidaturenAufListenBetrachtet) {
          Ersatzkandidatur listenkandidaturBevollmaechtigter = new NlListenkandidatur(listenkandidatur).getBevollmaechtigter();

          if (listenkandidaturBevollmaechtigter != null) {
            this.kandidaturBevollmaechtigterDokumentPerKandidatur.put(listenkandidatur.getPk(),
                this.wahlCustomDataDocument.createKandidaturOhneWahlvorschlagDokument(wasElectContext, wahlvorschlagCoreDaten, listenkandidaturBevollmaechtigter));
          }
        }
      }
    }
  }

  private NlErgebnisDatenCustomDataDocumentContext getContext() {
    return context;
  }

  private NlErgebnisDaten getNlErgebnisDaten() {
    return getContext().getNlErgebnisDaten();
  }

  private NlErgebnisDatenGueltige getNlErgebnisDatenGueltige() {
    return getContext().getNlErgebnisDatenGueltige();
  }

  private NlErgebnisDatenStimmzettel getNlErgebnisDatenStimmzettel() {
    return getContext().getNlErgebnisDatenStimmzettel();
  }

  @DocumentMethod
  public boolean isErfassungsgebieteVorhandenNurUrnenwahl() {
    return !erfassungsgebieteMitListenNurUrnenwahl.isEmpty();
  }

  @DocumentMethod
  public boolean isErfassungsgebieteVorhandenNurBriefwahlGemeinde() {
    return !erfassungsgebieteMitListenNurBriefwahlGemeinde.isEmpty();
  }

  @DocumentMethod
  public boolean isErfassungsgebieteVorhandenNurBriefwahlAusland() {
    return !erfassungsgebieteMitListenNurBriefwahlAusland.isEmpty();
  }

  @DocumentMethod // ELECT-11588
  public String formatKandidaturNamenAufStimmzettel(@DocumentParam("kandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(wahlCustomDataDocument::formatKandidaturNamenAufStimmzettel).orElse("");
  }
  
  @DocumentMethod // ELECT-11588
  public String formatKandidaturVornamenAufStimmzettel(@DocumentParam("kandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(wahlCustomDataDocument::formatKandidaturVornamenAufStimmzettel).orElse("");
  }

  @DocumentMethod // ELECT-16953
  public String formatKandidaturWohnortMitStaatImAusland(@DocumentParam("kandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(wahlCustomDataDocument::formatKandidaturWohnortMitStaatImAusland).orElse("");
  }

  @DocumentMethod
  public List<String> getP7KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP7Konflikt);
  }

  @DocumentMethod
  public List<String> getP8KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP8Konflikt);
  }

  @DocumentMethod
  public List<String> getP9KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP9Konflikt);
  }

  @DocumentMethod
  public List<String> getP10KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP10Konflikt);
  }

  @DocumentMethod
  public List<String> getP12KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP12Konflikt);
  }

  @DocumentMethod
  public List<String> getP13KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP13Konflikt);
  }

  @DocumentMethod
  public List<String> getP15KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP15Konflikt);
  }

  @DocumentMethod
  public List<String> getP16KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP16Konflikt);
  }

  @DocumentMethod
  public List<String> getP18KonflikteFuerGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return getKonflikteInnerhalbDerGruppe(gruppeReference, this::isP18Konflikt);
  }

  private List<String> getKonflikteInnerhalbDerGruppe(Object gruppeReference, Predicate<NlErgebnisKonfliktDocument> isKonfliktFunction) {
    return findPolitischeGruppe(gruppeReference)
        .map(gruppe -> nlErgebnisKonflikte.stream().filter(konflikt -> isKonfliktFunction.test(konflikt) && istKonfliktInnerhalbDerGruppe(gruppe, konflikt)).map(k -> k.beschreibung))
        .orElse(Stream.empty()).collect(toList());
  }

  private Boolean istKonfliktInnerhalbDerGruppe(PolitischeGruppe gruppe, NlErgebnisKonfliktDocument konfliktDocument) {
    if (konfliktDocument.isKandidaturEntscheidung()) {
      return findListenkandidatur(konfliktDocument.gelosteKandidatur).map(listenkandidatur -> listenkandidaturGehoertZurGruppe(listenkandidatur, gruppe)).orElse(false);
    } else if (konfliktDocument.isP2ListeEntscheidung()) {
      return findListe(konfliktDocument.gelosteListe).map(liste -> listeGehoertZurListe(liste, gruppe)).orElse(false);
    }
    return false;
  }

  private boolean listeGehoertZurListe(Liste liste, PolitischeGruppe gruppe) {
    if (gruppe == null) {
      return false;
    }
    return gruppe.equals(liste.getGruppe());
  }

  private boolean listenkandidaturGehoertZurGruppe(Listenkandidatur listenkandidatur, PolitischeGruppe gruppe) {
    if (gruppe == null) {
      return false;
    }
    return gruppe.equals(listenkandidatur.getGruppe());
  }

  @DocumentMethod
  public boolean isP7Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P7);
  }

  @DocumentMethod
  public boolean isP8Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P8);
  }

  @DocumentMethod
  public boolean isP9Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P9);
  }

  @DocumentMethod
  public boolean isP10Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P10);
  }

  @DocumentMethod
  public boolean isP12Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P12);
  }

  @DocumentMethod
  public boolean isP13Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P13);
  }

  @DocumentMethod
  public boolean isP15Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P15);
  }

  @DocumentMethod
  public boolean isP16Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P16);
  }

  @DocumentMethod
  public boolean isP18Konflikt(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference) {
    return isKonfliktMitArtikelnummer(konfliktReference, OsvLegacyArtikelnummer.P18);
  }

  private Boolean isKonfliktMitArtikelnummer(@DocumentParam("ergebnisKonfliktDokument") Object konfliktReference, OsvLegacyArtikelnummer artikelnummer) {
    return findeKonflikt(konfliktReference).map(k -> isArtikelnummer(k, artikelnummer)).orElse(false);
  }

  private Optional<ErgebnisKonflikt> findeKonflikt(Object konfliktReference) {
    if (konfliktReference instanceof NlErgebnisKonfliktDocument) {
      NlErgebnisKonfliktDocument konfliktDocument = (NlErgebnisKonfliktDocument) konfliktReference;

      return getNlErgebnisDaten().getKonflikte().stream().filter(k -> k.getCustomData(OsvLegacyKonfliktCustomData.class).getPosition().equals(konfliktDocument.position)).findAny();
    }

    return Optional.empty();
  }

  private boolean isArtikelnummer(ErgebnisKonflikt an, OsvLegacyArtikelnummer artikelnummer) {
    return an.getCustomData(OsvLegacyKonfliktCustomData.class).getArtikelnummer().equals(artikelnummer);
  }

  @DocumentMethod
  public Boolean isGruppeIdentischerListe(@DocumentParam("gruppe") Object gruppeReference) {
    return findPolitischeGruppe(gruppeReference).filter(gruppe -> getNlErgebnisDaten().getNlPolitischeGruppeArt(gruppe).isIdentischeListe()).isPresent();
  }

  @DocumentMethod
  public Boolean isEinzelneListe(@DocumentParam("gruppe") Object gruppeReference) {
    return findPolitischeGruppe(gruppeReference).filter(gruppe -> getNlErgebnisDaten().getNlPolitischeGruppeArt(gruppe).isEinzelliste()).isPresent();
  }

  @DocumentMethod
  public Boolean isGruppeEinTeilnehmerInWahlkreis(@DocumentParam("gruppe") Object gruppeReference, @DocumentParam("wahlkreisNummer") String wahlkreisNummer) {
    return collectListePerWahlkreis(gruppeReference).keySet().stream().anyMatch(wahlkreis -> getContext().existsWahlkreis(wahlkreis, wahlkreisNummer));
  }

  @DocumentMethod
  public String getHashCodeEml520() {
    return getHashCode(getFileFormatEml520());
  }

  @DocumentMethod
  public String getHashCodeEml520ByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getHashCodeByGebiet(getFileFormatEml520(), gebietReference);
  }

  private FileFormat getFileFormatEml520() {
    return Eml520ErgebnisExportMapper.FILE_FORMAT;
  }

  @DocumentMethod
  public String getHashCodeEml510() {
    return firstNonBlank(getHashCodeEml510d(), getHashCodeEml510c(), getHashCodeEml510b());
  }

  @DocumentMethod
  public String getHashCodeEml510ByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return firstNonBlank(getHashCodeEml510dByGebiet(gebietReference), getHashCodeEml510cByGebiet(gebietReference), getHashCodeEml510bByGebiet(gebietReference));
  }

  /**
   * @see NlErgebnisDatenCustomDataDocument#getHashCodeEml510!!!
   */
  @DocumentMethod
  public String getHashCodeEml510b() {
    return getHashCode(getFileFormatEml510b());
  }

  /**
   * @see NlErgebnisDatenCustomDataDocument#getHashCodeEml510ByGebiet!!!
   */
  @DocumentMethod
  public String getHashCodeEml510bByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getHashCodeByGebiet(getFileFormatEml510b(), gebietReference);
  }

  private FileFormat getFileFormatEml510b() {
    List<FileFormat> fileFormatsSortedByRelevanz = asList( //
        Eml510bGSBErgebnisExportMapper.FILE_FORMAT, //
        Eml510bHSBErgebnisExportMapper.FILE_FORMAT //
    );

    for (FileFormat fileFormat : fileFormatsSortedByRelevanz) {
      if (existsHashCode(fileFormat)) {
        return fileFormat;
      }
    }

    info("KEIN EML-510b-FileFormat gefunden [wahlebeneCSB = {}, wahlebeneHSB = {}, wahlebeneGSB = {}, fileFormats = {}]", wahlCustomDataDocument.wahlebeneCSB, wahlCustomDataDocument.wahlebeneHSB,
        wahlCustomDataDocument.wahlebeneGSB, fileFormatsSortedByRelevanz);

    return FILE_FORMAT_EML_UNBEKANNT;
  }

  /**
   * @see NlErgebnisDatenCustomDataDocument#getHashCodeEml510!!!
   */
  @DocumentMethod
  public String getHashCodeEml510c() {
    return getHashCode(getFileFormatEml510c());
  }

  /**
   * @see NlErgebnisDatenCustomDataDocument#getHashCodeEml510ByGebiet!!!
   */
  @DocumentMethod
  public String getHashCodeEml510cByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getHashCodeByGebiet(getFileFormatEml510c(), gebietReference);
  }

  private FileFormat getFileFormatEml510c() {
    List<FileFormat> fileFormatsSortedByRelevanz = asList( //
        Eml510cHSBErgebnisExportMapper.FILE_FORMAT, //
        Eml510cCSBErgebnisExportMapper.FILE_FORMAT //
    );

    for (FileFormat fileFormat : fileFormatsSortedByRelevanz) {
      if (existsHashCode(fileFormat)) {
        return fileFormat;
      }
    }

    info("KEIN EML-510c-FileFormat gefunden [wahlebeneCSB = {}, wahlebeneHSB = {}, wahlebeneGSB = {}, fileFormats = {}]", wahlCustomDataDocument.wahlebeneCSB, wahlCustomDataDocument.wahlebeneHSB,
        wahlCustomDataDocument.wahlebeneGSB, fileFormatsSortedByRelevanz);

    return FILE_FORMAT_EML_UNBEKANNT;
  }

  /**
   * @see NlErgebnisDatenCustomDataDocument#getHashCodeEml510!!!
   */
  @DocumentMethod
  public String getHashCodeEml510d() {
    return getHashCode(getFileFormatEml510d());
  }

  /**
   * @see NlErgebnisDatenCustomDataDocument#getHashCodeEml510ByGebiet!!!
   */
  @DocumentMethod
  public String getHashCodeEml510dByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getHashCodeByGebiet(getFileFormatEml510d(), gebietReference);
  }

  private FileFormat getFileFormatEml510d() {
    return Eml510dCSBErgebnisExportMapper.FILE_FORMAT;
  }

  private boolean existsHashCode(FileFormat fileFormat) {
    return wahlCustomDataDocument.existsHashCode(fileFormat);
  }

  private String getHashCode(FileFormat fileFormat) {
    return wahlCustomDataDocument.getHashCode(fileFormat);
  }

  private String getHashCodeByGebiet(FileFormat fileFormat, Object gebietReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> wahlCustomDataDocument.getHashCode(fileFormat, wahldurchfuehrungsgebiet)).orElse("");
  }

  private List<NlErgebnisKonfliktDocument> createErgebnisKonflikteDocuments(ErgebnisDaten ergebnisDaten, Map<Liste, ListeMitStimmergebnissenDocument> ergebnisDokumentPerListe,
      Map<Kandidatur, KandidaturMitStimmergebnissenDocument> ergebnisDokumentPerKandidatur, Messages messages) {
    return ergebnisDaten.getKonflikte().stream().map(k -> new NlErgebnisKonfliktDocument(ergebnisDaten, k, ergebnisDokumentPerListe, ergebnisDokumentPerKandidatur, messages)).collect(toList());
  }

  @DocumentMethod
  public Date calculateDateTimeInZoneId(@DocumentParam("dateTime") Date date, Object zoneId) {
    return wahlCustomDataDocument.calculateDateTimeInZoneId(date, zoneId);
  }

  @DocumentMethod // ELECT-10603
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenig() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenig(getStimmabgabeart(), erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-11573
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurGesamtGemeinde() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart.GESAMT, NlErgebnisDaten.ERFASSUNGSGEBIET_GEMEINDE);
  }

  @DocumentMethod // ELECT-10603
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurUrnenwahl() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart.URNE, erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-10603
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahl() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(erfassungsgebiet -> true);
  }

  @DocumentMethod
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahlGemeinde() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_GEMEINDE);
  }

  @DocumentMethod
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahlAusland() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_AUSLAND);
  }

  private List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(Predicate<Gebiet> erfassungsgebietFilter) {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart.BRIEF, erfassungsgebietFilter);
  }

  private List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart stimmabgabeart, Predicate<Gebiet> erfassungsgebietFilter) {
    return getErfassungsgebieteHavingAnzahlGroesserNull(this::getAnzahlStimmzettelEingenommenAbweichendZuwenig, stimmabgabeart, erfassungsgebietFilter);
  }

  @DocumentMethod // ELECT-10603
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenig() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenig(getStimmabgabeart(), erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-11573
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurGesamtGemeinde() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart.GESAMT, NlErgebnisDaten.ERFASSUNGSGEBIET_GEMEINDE);
  }

  @DocumentMethod // ELECT-10603
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurUrnenwahl() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart.URNE, erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-10603
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahl() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(erfassungsgebiet -> true);
  }

  @DocumentMethod
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahlGemeinde() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_GEMEINDE);
  }

  @DocumentMethod
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahlAusland() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_AUSLAND);
  }

  private Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenigNurBriefwahl(Predicate<Gebiet> erfassungsgebietFilter) {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart.BRIEF, erfassungsgebietFilter);
  }

  private Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuwenig(Stimmabgabeart stimmabgabeart, Predicate<Gebiet> erfassungsgebietFilter) {
    return getSummeInErfassungsgebieten(this::getAnzahlStimmzettelEingenommenAbweichendZuwenig, stimmabgabeart, erfassungsgebietFilter);
  }

  @DocumentMethod // ELECT-10603
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuviel() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuviel(getStimmabgabeart(), erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-11573
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurGesamtGemeinde() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart.GESAMT, NlErgebnisDaten.ERFASSUNGSGEBIET_GEMEINDE);
  }

  @DocumentMethod // ELECT-10603
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurUrnenwahl() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart.URNE, erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-10603
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahl() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahl(erfassungsgebiet -> true);
  }

  @DocumentMethod
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahlGemeinde() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_GEMEINDE);
  }

  @DocumentMethod
  public List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahlAusland() {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_AUSLAND);
  }

  private List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuvielNurBriefwahl(Predicate<Gebiet> erfassungsgebietFilter) {
    return getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart.BRIEF, erfassungsgebietFilter);
  }

  private List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart stimmabgabeart, Predicate<Gebiet> erfassungsgebietFilter) {
    return getErfassungsgebieteHavingAnzahlGroesserNull(this::getAnzahlStimmzettelEingenommenAbweichendZuviel, stimmabgabeart, erfassungsgebietFilter);
  }

  @DocumentMethod // ELECT-10603
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuviel() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuviel(getStimmabgabeart(), erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-11573
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurGesamtGemeinde() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart.GESAMT, NlErgebnisDaten.ERFASSUNGSGEBIET_GEMEINDE);
  }

  @DocumentMethod // ELECT-10603
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurUrnenwahl() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart.URNE, erfassungsgebiet -> true);
  }

  @DocumentMethod // ELECT-10603
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahl() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahl(erfassungsgebiet -> true);
  }

  @DocumentMethod
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahlGemeinde() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_GEMEINDE);
  }

  @DocumentMethod
  public Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahlAusland() {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahl(NlErgebnisDaten.ERFASSUNGSGEBIET_BRIEFWAHL_AUSLAND);
  }

  private Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuvielNurBriefwahl(Predicate<Gebiet> erfassungsgebietFilter) {
    return getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart.BRIEF, erfassungsgebietFilter);
  }

  private Long getSummeInErfassungsgebietenStimmzettelEingenommenAbweichendZuviel(Stimmabgabeart stimmabgabeart, Predicate<Gebiet> erfassungsgebietFilter) {
    return getSummeInErfassungsgebieten(this::getAnzahlStimmzettelEingenommenAbweichendZuviel, stimmabgabeart, erfassungsgebietFilter);
  }

  private List<GebietMitListenDocument> getErfassungsgebieteHavingAnzahlGroesserNull(BiFunction<GebietMitListenDocument, Stimmabgabeart, Long> anzahlFct, Stimmabgabeart stimmabgabeart,
      Predicate<Gebiet> erfassungsgebietFilter) {
    return new ArrayList<>(getAnzahlGroesserNullPerErfassungsgebiet(anzahlFct, stimmabgabeart, erfassungsgebietFilter).keySet());
  }

  private long getSummeInErfassungsgebieten(BiFunction<GebietMitListenDocument, Stimmabgabeart, Long> anzahlFct, Stimmabgabeart stimmabgabeart, Predicate<Gebiet> erfassungsgebietFilter) {
    return getAnzahlGroesserNullPerErfassungsgebiet(anzahlFct, stimmabgabeart, erfassungsgebietFilter).values().stream().collect(summarizingLong(Long::longValue)).getSum();
  }

  private LinkedHashMap<GebietMitListenDocument, Long> getAnzahlGroesserNullPerErfassungsgebiet(BiFunction<GebietMitListenDocument, Stimmabgabeart, Long> anzahlFct, Stimmabgabeart stimmabgabeart,
      Predicate<Gebiet> erfassungsgebietFilter) {
    LinkedHashMap<GebietMitListenDocument, Long> result = new LinkedHashMap<>(); // Reihenfolge erhalten...

    for (GebietMitListenDocument gebietMitListenDocument : filterErfassungsgebiete(erfassungsgebieteMitListen, erfassungsgebietFilter)) {
      Long anzahl = anzahlFct.apply(gebietMitListenDocument, stimmabgabeart);

      if (anzahl != null && anzahl > 0) {
        result.put(gebietMitListenDocument, anzahl);
      }
    }

    return result;
  }

  @DocumentMethod
  public Long getAnzahlListenstimmenVorperiodeByGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return wahlCustomDataDocument.getAnzahlListenstimmenVorperiodeByGruppe(gruppeReference);
  }

  @DocumentMethod
  public Long getAnzahlWahlberechtigteGesamtByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWahlberechtigteGesamt(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlWahlberechtigteGesamtByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.WAHLBERECHTIGTE)) {
      return null;
    }
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWahlberechtigteGesamtNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlWahlberechtigteGesamtByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWahlberechtigteGesamt(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod // JA, auch bei BRIEFWAHL!
  public Long getAnzahlWahlberechtigteGesamtByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWahlberechtigteGesamt(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod // JA, auch bei BRIEFWAHL!
  public Long getAnzahlWahlberechtigteGesamtByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWahlberechtigteGesamtNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod // JA, auch bei BRIEFWAHL!
  public Long getAnzahlWahlberechtigteGesamtByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWahlberechtigteGesamtNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlWahlberechtigteGesamt(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDaten().getSummeWahlberechtigteGesamt(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerOhneWahlscheinByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWaehlerOhneWahlschein(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlWaehlerOhneWahlscheinByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWaehlerOhneWahlscheinNurGesamtGemeinde).orElse(0L);
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlWaehlerOhneWahlscheinByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.WAEHLER_OHNE_WAHLSCHEIN)) {
      return null;
    }

    return getAnzahlWaehlerOhneWahlschein(gebietReference, Stimmabgabeart.URNE);
  }

  private Long getAnzahlWaehlerOhneWahlschein(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDaten().getSummeWaehlerOhneWahlschein(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerMitWahlscheinByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWaehlerMitWahlschein(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlWaehlerMitWahlscheinByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWaehlerMitWahlscheinNurGesamtGemeinde).orElse(0L);
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlWaehlerMitWahlscheinByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.WAEHLER_MIT_WAHLSCHEIN)) {
      return null;
    }

    return getAnzahlWaehlerMitWahlschein(gebietReference, Stimmabgabeart.URNE);
  }

  private Long getAnzahlWaehlerMitWahlschein(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDaten().getSummeWaehlerMitWahlschein(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerMitVollmachtByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWaehlerMitVollmacht(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlWaehlerMitVollmachtByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWaehlerMitVollmachtNurGesamtGemeinde).orElse(0L);
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlWaehlerMitVollmachtByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.WAEHLER_MIT_VOLLMACHT)) {
      return null;
    }
    return getAnzahlWaehlerMitVollmacht(gebietReference, Stimmabgabeart.URNE);
  }

  private Long getAnzahlWaehlerMitVollmacht(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDaten().getSummeWaehlerMitVollmacht(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerGesamtByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWaehlerGesamt(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlWaehlerGesamtByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWaehlerGesamtNurGesamtGemeinde).orElse(0L);
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlWaehlerGesamtByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.WAEHLER_GESAMT)) {
      return null;
    }

    return getAnzahlWaehlerGesamt(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerGesamtByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlWaehlerGesamt(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerGesamtByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWaehlerGesamtNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlWaehlerGesamtByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDaten()::getSummeWaehlerGesamtNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlWaehlerGesamt(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDaten().getSummeWaehlerGesamt(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlGueltigeListenstimmen(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlGueltigeListenstimmenGewichtetMitVoteValues(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.GUELTIGE_INSGESAMT)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeGueltigeListenstimmenNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurGesamtGemeindeGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeGueltigeListenstimmenNurGesamtGemeindeGewichtetMitVoteValues).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlGueltigeListenstimmen(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurUrnenwahlGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlGueltigeListenstimmenGewichtetMitVoteValues(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlGueltigeListenstimmen(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurBriefwahlGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlGueltigeListenstimmenGewichtetMitVoteValues(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeGueltigeListenstimmenNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurBriefwahlGemeindeGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeGueltigeListenstimmenNurBriefwahlGemeindeGewichtetMitVoteValues).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeGueltigeListenstimmenNurBriefwahlAusland).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlGueltigeListenstimmenByGebietNurBriefwahlAuslandGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeGueltigeListenstimmenNurBriefwahlAuslandGewichtetMitVoteValues).orElse(0L);
  }

  private Long getAnzahlGueltigeListenstimmen(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenGueltige().getSummeGueltigeListenstimmen(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  private Long getAnzahlGueltigeListenstimmenGewichtetMitVoteValues(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenGueltige().getSummeGueltigeListenstimmenGewichtetMitVoteValues(wahldurchfuehrungsgebiet, stimmabgabeart))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlUngueltigeListenstimmenByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlUngueltigeListenstimmen(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlUngueltigeListenstimmenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.UNGUELTIGE)) {
      return null;
    }
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeUngueltigeListenstimmenNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlUngueltigeListenstimmenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlUngueltigeListenstimmen(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlUngueltigeListenstimmenByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlUngueltigeListenstimmen(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlUngueltigeListenstimmenByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeUngueltigeListenstimmenNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlUngueltigeListenstimmenByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeUngueltigeListenstimmenNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlUngueltigeListenstimmen(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenGueltige().getSummeUngueltigeListenstimmen(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlBlankoListenstimmenByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlBlankoListenstimmen(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlBlankoListenstimmenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.BLANCO)) {
      return null;
    }
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeBlankoListenstimmenNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlBlankoListenstimmenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlBlankoListenstimmen(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlBlankoListenstimmenByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlBlankoListenstimmen(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlBlankoListenstimmenByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeBlankoListenstimmenNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlBlankoListenstimmenByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenGueltige()::getSummeBlankoListenstimmenNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlBlankoListenstimmen(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenGueltige().getSummeBlankoListenstimmen(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenGesamtByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenGesamt(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenGesamtByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenGesamtNurGesamtGemeinde).orElse(0L);
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenGesamtByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.WAEHLER_OHNE_WAHLSCHEIN) && isValueTypeFiltered(NlVoteType.WAEHLER_MIT_VOLLMACHT) && isValueTypeFiltered(NlVoteType.WAEHLER_MIT_WAHLSCHEIN)) {
      return null;
    }
    return getAnzahlStimmzettelEingenommenGesamt(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenGesamtByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenGesamt(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenGesamtByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenGesamtNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenGesamtByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenGesamtNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenGesamt(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenGesamt(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuvielByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendZuviel(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  @Nullable
  public Long getAnzahlStimmzettelEingenommenAbweichendZuvielByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_EINGENOMMEN_ZU_VIEL)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendZuvielNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuvielByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendZuviel(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuvielByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendZuviel(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuvielByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendZuvielNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuvielByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendZuvielNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendZuviel(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendZuviel(wahldurchfuehrungsgebiet, stimmabgabeart))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuwenigByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendZuwenig(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuwenigByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_EINGENOMMEN_ZU_WENIG)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendZuwenigNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuwenigByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendZuwenig(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuwenigByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendZuwenig(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuwenigByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendZuwenigNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendZuwenigByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendZuwenigNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendZuwenig(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendZuwenig(wahldurchfuehrungsgebiet, stimmabgabeart))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegebenByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegebenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_NICHT_ABGEGEBEN)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegebenNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegebenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben(gebietReference, Stimmabgabeart.URNE);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuvielByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuviel(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuvielByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_ZU_VIEL_AUSGEGEBEN)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundAusgegebenZuvielNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuvielByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuviel(gebietReference, Stimmabgabeart.URNE);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuviel(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundAusgegebenZuviel(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuwenigByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  @Nullable
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuwenigByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_ZU_WENIG_AUSGEGEBEN)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundAusgegebenZuwenigNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuwenigByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig(gebietReference, Stimmabgabeart.URNE);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig(wahldurchfuehrungsgebiet, stimmabgabeart)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundVerlorenByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundVerloren(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundVerlorenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundVerlorenNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundVerlorenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundVerloren(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundVerlorenByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundVerloren(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundVerlorenByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundVerlorenNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundVerlorenByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundVerlorenNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundVerloren(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundVerloren(wahldurchfuehrungsgebiet, stimmabgabeart))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekanntByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundUnbekannt(gebietReference, getStimmabgabeart());
  }

  @DocumentMethod
  @Nullable
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekanntByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_ABWEICHEND_UNBEKANNTER_GRUND)) {
      return null;
    }
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundUnbekanntNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekanntByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundUnbekannt(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekanntByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundUnbekannt(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekanntByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundUnbekanntNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekanntByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundUnbekanntNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundUnbekannt(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundUnbekannt(wahldurchfuehrungsgebiet, stimmabgabeart))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstigesByGebiet(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundSonstiges(gebietReference, getStimmabgabeart());
  }

  @Nullable
  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstigesByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference) {

    if (isValueTypeFiltered(NlVoteType.STIMMZETTEL_ABWEICHEND_ANDERER_GRUND)) {
      return null;
    }

    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundSonstigesNurGesamtGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstigesByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundSonstiges(gebietReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstigesByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference) {
    return getAnzahlStimmzettelEingenommenAbweichendGrundSonstiges(gebietReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstigesByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundSonstigesNurBriefwahlGemeinde).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstigesByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference) {
    return findGebiet(gebietReference).map(getNlErgebnisDatenStimmzettel()::getSummeStimmzettelEingenommenAbweichendGrundSonstigesNurBriefwahlAusland).orElse(0L);
  }

  private Long getAnzahlStimmzettelEingenommenAbweichendGrundSonstiges(Object gebietReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> getNlErgebnisDatenStimmzettel().getSummeStimmzettelEingenommenAbweichendGrundSonstiges(wahldurchfuehrungsgebiet, stimmabgabeart))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietsnummer(@DocumentParam("wahlkreisNummer") String wahlkreisNummer, @DocumentParam("gruppe") Object gruppeReference) {
    return collectListePerWahlkreis(gruppeReference).entrySet().stream() //
        .filter(entry -> getContext().existsWahlkreis(entry.getKey(), wahlkreisNummer)) //
        .findAny() //
        .map(entry -> getAnzahlListeListenstimmenByGebiet(entry.getKey(), entry.getValue(), getStimmabgabeart())).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietsnummerGewichtetMitVoteValues(@DocumentParam("wahlkreisNummer") String wahlkreisNummer, @DocumentParam("gruppe") Object gruppeReference) {
    return collectListePerWahlkreis(gruppeReference).entrySet().stream() //
        .filter(entry -> getContext().existsWahlkreis(entry.getKey(), wahlkreisNummer)) //
        .findAny() //
        .map(entry -> getAnzahlListeListenstimmenByGebietGewichtetMitVoteValues(entry.getKey(), entry.getValue(), getStimmabgabeart())).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebiet(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return getAnzahlListeListenstimmenByGebiet(gebietReference, wahlvorschlagReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return getAnzahlListeListenstimmenByGebietGewichtetMitVoteValues(gebietReference, wahlvorschlagReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference).map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenNurGesamtGemeinde(wahldurchfuehrungsgebiet, liste)).orElse(0L))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurGesamtGemeindeGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference)
        .map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenNurGesamtGemeindeGewichtetMitVoteValues(wahldurchfuehrungsgebiet, liste)).orElse(0L)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return getAnzahlListeListenstimmenByGebiet(gebietReference, wahlvorschlagReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurUrnenwahlGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return getAnzahlListeListenstimmenByGebietGewichtetMitVoteValues(gebietReference, wahlvorschlagReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return getAnzahlListeListenstimmenByGebiet(gebietReference, wahlvorschlagReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurBriefwahlGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return getAnzahlListeListenstimmenByGebietGewichtetMitVoteValues(gebietReference, wahlvorschlagReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return findGebiet(gebietReference)
        .map(
            wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference).map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenNurBriefwahlGemeinde(wahldurchfuehrungsgebiet, liste)).orElse(0L))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurBriefwahlGemeindeGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference)
        .map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenNurBriefwahlGemeindeGewichtetMitVoteValues(wahldurchfuehrungsgebiet, liste)).orElse(0L)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference).map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenNurBriefwahlAusland(wahldurchfuehrungsgebiet, liste)).orElse(0L))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListeListenstimmenByGebietNurBriefwahlAuslandGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("liste") Object wahlvorschlagReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference)
        .map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenNurBriefwahlAuslandGewichtetMitVoteValues(wahldurchfuehrungsgebiet, liste)).orElse(0L)).orElse(0L);
  }

  private Long getAnzahlListeListenstimmenByGebiet(Object gebietReference, Object wahlvorschlagReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference).map(liste -> getNlErgebnisDaten().getSummeListeListenstimmen(wahldurchfuehrungsgebiet, stimmabgabeart, liste)).orElse(0L))
        .orElse(0L);
  }

  private Long getAnzahlListeListenstimmenByGebietGewichtetMitVoteValues(Object gebietReference, Object wahlvorschlagReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListe(wahlvorschlagReference)
        .map(liste -> getNlErgebnisDaten().getSummeListeListenstimmenGewichtetMitVoteValues(wahldurchfuehrungsgebiet, stimmabgabeart, liste)).orElse(0L)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebiet(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return getAnzahlListenkandidaturListenstimmenByGebiet(gebietReference, kandidaturReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return getAnzahlListenkandidaturListenstimmenByGebietGewichtetMitVoteValues(gebietReference, kandidaturReference, getStimmabgabeart());
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurGesamtGemeinde(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
        .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenNurGesamtGemeinde(wahldurchfuehrungsgebiet, listenkandidatur)).orElse(0L)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurGesamtGemeindeGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference,
      @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
            .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenNurGesamtGemeindeGewichtetMitVoteValues(wahldurchfuehrungsgebiet, listenkandidatur)).orElse(0L))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurUrnenwahl(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return getAnzahlListenkandidaturListenstimmenByGebiet(gebietReference, kandidaturReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurUrnenwahlGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference,
      @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return getAnzahlListenkandidaturListenstimmenByGebietGewichtetMitVoteValues(gebietReference, kandidaturReference, Stimmabgabeart.URNE);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurBriefwahl(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return getAnzahlListenkandidaturListenstimmenByGebiet(gebietReference, kandidaturReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurBriefwahlGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference,
      @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return getAnzahlListenkandidaturListenstimmenByGebietGewichtetMitVoteValues(gebietReference, kandidaturReference, Stimmabgabeart.BRIEF);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurBriefwahlGemeinde(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
        .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenNurBriefwahlGemeinde(wahldurchfuehrungsgebiet, listenkandidatur)).orElse(0L)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurBriefwahlGemeindeGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference,
      @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
            .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenNurBriefwahlGemeindeGewichtetMitVoteValues(wahldurchfuehrungsgebiet, listenkandidatur)).orElse(0L))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurBriefwahlAusland(@DocumentParam("gebiet") Object gebietReference, @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
        .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenNurBriefwahlAusland(wahldurchfuehrungsgebiet, listenkandidatur)).orElse(0L)).orElse(0L);
  }

  @DocumentMethod
  public Long getAnzahlListenkandidaturListenstimmenByGebietNurBriefwahlAuslandGewichtetMitVoteValues(@DocumentParam("gebiet") Object gebietReference,
      @DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
            .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenNurBriefwahlAuslandGewichtetMitVoteValues(wahldurchfuehrungsgebiet, listenkandidatur)).orElse(0L))
        .orElse(0L);
  }

  private Long getAnzahlListenkandidaturListenstimmenByGebiet(Object gebietReference, Object kandidaturReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference).map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
        .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmen(wahldurchfuehrungsgebiet, stimmabgabeart, listenkandidatur)).orElse(0L)).orElse(0L);
  }

  private Long getAnzahlListenkandidaturListenstimmenByGebietGewichtetMitVoteValues(Object gebietReference, Object kandidaturReference, Stimmabgabeart stimmabgabeart) {
    return findGebiet(gebietReference)
        .map(wahldurchfuehrungsgebiet -> findListenkandidatur(kandidaturReference)
            .map(listenkandidatur -> getNlErgebnisDaten().getSummeListenkandidaturListenstimmenGewichtetMitVoteValues(wahldurchfuehrungsgebiet, stimmabgabeart, listenkandidatur)).orElse(0L))
        .orElse(0L);
  }

  @DocumentMethod
  public Long getGesamtstimmenFuerKandidat(@DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(listenkandidatur -> getNlErgebnisDaten().getSummeKandidatListenstimmen(getStimmabgabeart(), listenkandidatur)).orElse(0L);
  }

  @DocumentMethod
  public Long getGesamtstimmenFuerKandidatGewichtetMitVoteValues(@DocumentParam("listenkandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(listenkandidatur -> getNlErgebnisDaten().getSummeKandidatListenstimmenGewichtetMitVoteValues(getStimmabgabeart(), listenkandidatur))
        .orElse(0L);
  }

  @DocumentMethod // ELECT-10557
  public Long getAnzahlErgebnisKonflikteGelostByArtikelnummer(@DocumentParam("artikelnummer") Object value) {
    long result = 0L;

    String artikelnummer = "";

    if (value instanceof String) {
      artikelnummer = (String) value;
    } else if (value instanceof NlErgebnisKonfliktDocument) {
      artikelnummer = ((NlErgebnisKonfliktDocument) value).artikelnummer;
    }

    artikelnummer = trimToEmpty(artikelnummer);

    if (isNotBlank(artikelnummer)) {
      for (NlErgebnisKonfliktDocument nlErgebnisKonfliktDocument : nlErgebnisKonflikte) {
        if (isNotBlank(nlErgebnisKonfliktDocument.losoptionGelost) && equalsIgnoreCase(trimToEmpty(nlErgebnisKonfliktDocument.artikelnummer), artikelnummer)) {
          result++;
        }
      }
    }

    return result;
  }

  @DocumentMethod
  public Boolean isGruppeEntscheidung(@DocumentParam("ErgebnisKonflikt") Object value) {
    if (value instanceof NlErgebnisKonfliktDocument) {
      return !((NlErgebnisKonfliktDocument) value).gelosteGruppe.equals(GruppeDokument.EMPTY_OBJECT);
    }

    return false;
  }

  @DocumentMethod
  public Boolean isListeEntscheidung(@DocumentParam("ErgebnisKonflikt") Object value) {
    if (value instanceof NlErgebnisKonfliktDocument) {
      return !((NlErgebnisKonfliktDocument) value).gelosteListe.equals(CoreWahlvorschlagsdatenDocument.EMPTY_OBJECT);
    }

    return false;
  }

  @DocumentMethod
  public Boolean isKandidaturEntscheidung(@DocumentParam("ErgebnisKonflikt") Object value) {
    if (value instanceof NlErgebnisKonfliktDocument) {
      return !((NlErgebnisKonfliktDocument) value).gelosteKandidatur.equals(CoreKandidaturDokument.EMPTY_OBJECT);
    }

    return false;
  }

  @DocumentMethod // ELECT-11942
  public boolean existsKandidaturBevollmaechtigterDokumentByKandidatur(@DocumentParam("kandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(Listenkandidatur::getPk).map(kandidaturBevollmaechtigterDokumentPerKandidatur::containsKey).orElse(false);
  }

  @DocumentMethod // ELECT-11942
  public KandidaturDokument getKandidaturBevollmaechtigterDokumentByKandidatur(@DocumentParam("kandidatur") Object kandidaturReference) {
    return findListenkandidatur(kandidaturReference).map(Listenkandidatur::getPk).map(kandidaturBevollmaechtigterDokumentPerKandidatur::get).orElse(KandidaturDokument.EMPTY_OBJECT);
  }

  @DocumentMethod // ELECT-10559
  public List<KandidaturDokument> getKandidaturDokumenteListenkandidaturenVerstorbenByGruppe(@DocumentParam("gruppe") Object gruppeReference) {
    return findPolitischeGruppe(gruppeReference).map(Gruppe::getPk).map(kandidaturOhneWahlvorschlagDokumentePerGruppe::get).orElse(emptyList()).stream() //
        .filter(kandidaturDokument -> kandidaturDokument.istZulassungNachZulassungsausschussVerloren) // Cf. NlWasKandidaturVerstorbenAction!
        .collect(toList());
  }

  private List<GebietMitListenDocument> createErfassungsgebieteMitListenDocuments(WasElectContext wasElectContext, ErgebnisDaten ergebnisDaten, List<Wahldurchfuehrungsgebiet> auswertungsgebiete,
      Map<Liste, ListeMitStimmergebnissenDocument> ergebnisDokumentPerListe, Map<Kandidatur, KandidaturMitStimmergebnissenDocument> ergebnisDokumentPerKandidatur) {
    List<GebietMitListenDocument> result = new ArrayList<>();

    Map<Listenverbindung, WasListenverbindungDokument> ergebnisDokumentPerListenverbindung = new HashMap<>();

    Set<Wahldurchfuehrungsgebiet> erfassungsgebiete = new HashSet<>();
    EntityAufStimmzettelDaten entityAufStimmzettelDaten = ergebnisDaten.getEntityAufStimmzettelDaten();

    for (Wahldurchfuehrungsgebiet auswertungsgebiet : auswertungsgebiete) {
      erfassungsgebiete.addAll(ergebnisDaten.getErfassungsgebieteUnterhalbVon(auswertungsgebiet));
    }

    List<Wahldurchfuehrungsgebiet> erfassungsgebieteSorted = new ArrayList<>(erfassungsgebiete);
    Collections.sort(erfassungsgebieteSorted, new GebietByPositionComparator());

    Map<Gebiet, GebietMitStimmenDocument> dokumentPerWahlgebietUebergeordnet = new HashMap<>();

    for (Wahldurchfuehrungsgebiet erfassungsgebiet : erfassungsgebieteSorted) {
      Gebiet wahlgebietUebergeordnet = erfassungsgebiet.getUebergeordnetesWahlgebiet();
      GebietMitStimmenDocument wahlgebietUebergeordnetDokument = null; // ELECT-10412

      if (wahlgebietUebergeordnet != null) {
        wahlgebietUebergeordnetDokument = dokumentPerWahlgebietUebergeordnet.computeIfAbsent(wahlgebietUebergeordnet,
            wahlgebiet -> new GebietMitStimmenDocument(wasElectContext, ergebnisDaten, new GebietUndStimmabgabeart(castTo(wahlgebiet, Wahldurchfuehrungsgebiet.class), getStimmabgabeart())));
      }

      result.add(new GebietMitListenDocument(wasElectContext, ergebnisDaten, new GebietUndStimmabgabeart(erfassungsgebiet, getStimmabgabeart()), wahlgebietUebergeordnetDokument,
          ergebnisDokumentPerListe, ergebnisDokumentPerListenverbindung, new KandidaturCoreDaten(wasElectContext, entityAufStimmzettelDaten), ergebnisDokumentPerKandidatur));
    }

    return result;
  }

  private SortedMap<Wahldurchfuehrungsgebiet, Liste> collectListePerWahlkreis(Object gruppeReference) {
    return findPolitischeGruppe(gruppeReference).map(getContext()::getListePerWahlkreis).orElse(emptySortedMap());
  }

  @Override
  public Optional<PolitischeGruppe> findPolitischeGruppe(Object gruppeReference) {
    Optional<PolitischeGruppe> result = wahlCustomDataDocument.findPolitischeGruppe(gruppeReference);

    if (result.isPresent()) {
      return result;
    }

    return super.findPolitischeGruppe(gruppeReference);
  }

  @Override
  public Optional<Wahldurchfuehrungsgebiet> findGebiet(Object gebietReference) {
    if (gebietReference instanceof Wahldurchfuehrungsgebiet) {
      return Optional.of((Wahldurchfuehrungsgebiet) gebietReference);
    }

    Optional<Wahldurchfuehrungsgebiet> result = wahlCustomDataDocument.findGebiet(gebietReference) //
        .map(gebiet -> Optional.of(castTo(gebiet, Wahldurchfuehrungsgebiet.class))) //
        .orElse(Optional.empty());

    if (result.isPresent()) {
      return result;
    }

    return super.findGebiet(gebietReference);
  }

  @Override
  public Optional<Liste> findListe(Object wahlvorschlagReference) {
    Optional<Liste> result = wahlCustomDataDocument.findListe(wahlvorschlagReference);

    if (result.isPresent()) {
      return result;
    }

    return super.findListe(wahlvorschlagReference);
  }

  @Override
  public Optional<Listenkandidatur> findListenkandidatur(Object kandidaturReference) {
    if (kandidaturReference instanceof NlKandidatStimmenDocument) {
      return Optional.ofNullable(((NlKandidatStimmenDocument) kandidaturReference).getListenkandidatur());
    }

    Optional<Listenkandidatur> result = wahlCustomDataDocument.findListenkandidatur(kandidaturReference);

    if (result.isPresent()) {
      return result;
    }

    return super.findListenkandidatur(kandidaturReference);
  }

  private static List<GebietMitListenDocument> filterErfassungsgebiete(List<GebietMitListenDocument> erfassungsgebieteMitListen, Predicate<Gebiet> erfassungsgebietFilter) {
    List<GebietMitListenDocument> result = new ArrayList<>();

    for (GebietMitListenDocument gebietMitListenDocument : erfassungsgebieteMitListen) {
      Gebiet gebiet = gebietMitListenDocument.getGebiet();

      if (gebiet != null && erfassungsgebietFilter.test(gebiet)) {
        result.add(gebietMitListenDocument);
      }
    }

    return result;
  }

  private boolean isValueTypeFiltered(NlVoteType nlVoteType) {
    return emlErgebnisDifferenz != null && !emlErgebnisDifferenz.getVoteTypeUnterschiede().containsKey(nlVoteType);
  }

  private boolean isValueTypeFiltered(Collection<NlVoteType> nlVoteTypes) {
    return nlVoteTypes.stream().allMatch(this::isValueTypeFiltered);
  }

  private static final Set<NlVoteType> ABSCHNITT_WAHLBERECHTIGTE_VOTE_TYPES = EnumSet.of(NlVoteType.WAHLBERECHTIGTE);

  private static final Set<NlVoteType> ABSCHNITT_STIMMZETTEL_VOTE_TYPES = EnumSet.of(NlVoteType.GUELTIGE_INSGESAMT, NlVoteType.UNGUELTIGE, NlVoteType.BLANCO);

  private static final Set<NlVoteType> ABSCHNITT_WAEHLER_VOTE_TYPES = EnumSet.of(NlVoteType.WAEHLER_OHNE_WAHLSCHEIN, NlVoteType.WAEHLER_MIT_VOLLMACHT, NlVoteType.WAEHLER_MIT_WAHLSCHEIN,
      NlVoteType.WAEHLER_GESAMT);

  private static final Set<NlVoteType> ABSCHNITT_ABWEICHUNGEN_VOTE_TYPES = EnumSet.of(NlVoteType.STIMMZETTEL_EINGENOMMEN_ZU_VIEL, NlVoteType.STIMMZETTEL_EINGENOMMEN_ZU_WENIG,
      NlVoteType.STIMMZETTEL_NICHT_ABGEGEBEN, NlVoteType.STIMMZETTEL_ZU_WENIG_AUSGEGEBEN, NlVoteType.STIMMZETTEL_ZU_VIEL_AUSGEGEBEN, NlVoteType.STIMMZETTEL_ABWEICHEND_UNBEKANNTER_GRUND,
      NlVoteType.STIMMZETTEL_ABWEICHEND_ANDERER_GRUND);

  public boolean isAbschnittWahlberechtigteEinblenden(@DocumentParam("gebiet") Object gebietReference) {
    return !isValueTypeFiltered(ABSCHNITT_WAHLBERECHTIGTE_VOTE_TYPES);
  }

  public boolean isAbschnittStimmzettelEinblenden(@DocumentParam("gebiet") Object gebietReference) {
    return !isValueTypeFiltered(ABSCHNITT_STIMMZETTEL_VOTE_TYPES);
  }

  public boolean isAbschnittWaehlerEinblenden(@DocumentParam("gebiet") Object gebietReference) {
    return !isValueTypeFiltered(ABSCHNITT_WAEHLER_VOTE_TYPES);
  }

  public boolean isAbschnittAbweichungenEinblenden(@DocumentParam("gebiet") Object gebietReference) {
    return !isValueTypeFiltered(ABSCHNITT_ABWEICHUNGEN_VOTE_TYPES);
  }
}
