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

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

import de.ivu.document.generator.template.annotations.Document;
import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentQueue;
import de.ivu.document.generator.template.annotations.DocumentRepeat;
import de.ivu.elect.business.dokumente.entity.DokumentVorlageArt;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;
import de.ivu.elect.dokumente.BaseElectContext;
import de.ivu.elect.dokumente.ergebnis.AbstractErgebnisTabellarischDocument;
import de.ivu.elect.dokumente.ergebnis.ErgebnisDocumentDatenArt;
import de.ivu.elect.dokumente.ergebnis.ErgebnisDocumentDatenGebietDocument;

@Document(DokumentVorlageArt.GESAMTERGEBNIS_V7_DOKUMENT_PREFIX)
public class ErgebnisGesamtergebnisTabellarischDocument extends AbstractErgebnisTabellarischDocument<ErgebnisGesamtergebnisTabellarischDocumentZeile> {

  private static final long serialVersionUID = 1L;

  public ErgebnisGesamtergebnisTabellarischDocumentDokumentVorlageArt dokumentVorlageArt;

  @DocumentRepeat(value = "Zeilen", elementClass = ErgebnisGesamtergebnisTabellarischDocumentZeile.class, itemName = "zeilenItem")
  public final List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilen;

  /**
   * A.k.a. Gruppe Schlüssel... (für ALLE Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNummer
   *
   * @deprecated Direkt-/Listenstimmen ggf. mit Lücken in den Stimmzettelposition!!!
   */
  @Deprecated
  @DocumentQueue(value = "ParteiStimmenSummeQueue-GruppeSchluesselLegacy", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNummer;

  /**
   * A.k.a. Gruppe Kurzname... (für ALLE Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameGruppe
   *
   * @deprecated ELECT-14679, Direkt-/Listenstimmen ggf. mit Lücken in den Stimmzettelposition!!!
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueNameGruppeErststimmen
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueNameGruppeZweitstimmen
   */
  @Deprecated
  @DocumentQueue(value = "ParteiStimmenSummeQueue-GruppeKurznameLegacy", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameGruppe;

  /**
   * A.k.a. Wahlvorschlag Kurzname oder Kennwort... (für ALLE Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameWahlvorschlag
   *
   * @deprecated ELECT-14679, Direkt-/Listenstimmen ggf. mit Lücken in den Stimmzettelposition!!!
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueNameDirektkandidat
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueNameDirektkandidatVollstaendig
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueNameListe
   */
  @Deprecated
  @DocumentQueue(value = "ParteiStimmenSummeQueue-WahlvorschlagKurznameOderKennwortLegacy", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameWahlvorschlag;

  /**
   * A.k.a. Wahlvorschlag Stimmzettelposition... (für ALLE Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueStimmzettelPositionWahlvorschlag
   *
   * @deprecated Direkt-/Listenstimmen ggf. mit Lücken in den Stimmzettelposition!!!
   */
  @Deprecated
  @DocumentQueue(value = "ParteiStimmenSummeQueue-WahlvorschlagStimmzettelPositionLegacy", elementClass = Long.class)
  public final LinkedList<Long> parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag;

  /**
   * D1, D2, ... (für ALLE Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueKennung
   *
   * @deprecated ELECT-12398, Direkt-/Listenstimmen ggf. mit Lücken in den Stimmzettelposition!!!
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueKennungErststimmen
   * @see ErgebnisGesamtergebnisTabellarischDocument#parteiStimmenSummeQueueKennungZweitstimmen
   */
  @Deprecated
  @DocumentQueue(value = "ParteiStimmenSummeQueue-WahlvorschlagKennungLegacy", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueKennung;

  /**
   * D01, D02, D04, ... (nur für existente Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueKennungErststimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenKennung", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueKennungErststimmen;

  /**
   * 01, 02, 04, ... (nur für existente Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueKennungPositionErststimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenKennungPosition", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueKennungPositionErststimmen;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueAnzahlErststimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenAnzahl", elementClass = Long.class)
  public final LinkedList<Long> parteiStimmenSummeQueueAnzahlErststimmen;

  /**
   * ELECT-14679
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameGruppeErststimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenGruppeKurzname", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameGruppeErststimmen;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameDirektkandidat
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenDirektkandidatFamilienname", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameDirektkandidat;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameDirektkandidatVollstaendig
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenDirektkandidatFamiliennameInklusiveTitelFamiliennameBestandteil", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameDirektkandidatVollstaendig; // ELECT-14337

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameDirektkandidatVorname
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-DirektstimmenDirektkandidatVorname", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameDirektkandidatVorname; // ELECT-16182

  /**
   * F01, F02, F04, ... (nur für existente Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueKennungZweitstimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-ListenstimmenKennung", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueKennungZweitstimmen;

  /**
   * 01, 02, 04, ... (nur für existente Stimmzettelpositionen)
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueKennungPositionZweitstimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-ListenstimmenKennungPosition", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueKennungPositionZweitstimmen;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueAnzahlZweitstimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-ListenstimmenAnzahl", elementClass = Long.class)
  public final LinkedList<Long> parteiStimmenSummeQueueAnzahlZweitstimmen;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-StimmzettelNurEinzelnerWahlvorschlagUnveraendertAnzahl", elementClass = Long.class)
  public LinkedList<Long> parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-StimmzettelNurEinzelnerWahlvorschlagVeraendertAnzahl", elementClass = Long.class)
  public LinkedList<Long> parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-StimmzettelNurEinzelnerWahlvorschlagPanaschiertAnzahl", elementClass = Long.class)
  public LinkedList<Long> parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert;

  /**
   * ELECT-14679
   *
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameGruppeZweitstimmen
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-ListenstimmenGruppeKurzname", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameGruppeZweitstimmen;

  /**
   * @see AbstractErgebnisGesamtergebnisTabellarischDocumentZeile#parteiStimmenQueueNameListe
   */
  @DocumentQueue(value = "ParteiStimmenSummeQueue-ListenstimmenListeKurznameOderKennwort", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameListe;

  @DocumentComplexField("Summen") // Eine einzelne Zeile mit den Summen
  public ErgebnisGesamtergebnisTabellarischDocumentZeileSummen ergebnisSummen;

  public ErgebnisGesamtergebnisTabellarischDocument(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, ErgebnisGesamtergebnisTabellarischDocumentDokumentVorlageArt dokumentVorlageArt,
      ErgebnisDocumentDatenGebietDocument datenGebiet, ErgebnisDocumentDatenArt datenArt) {
    super(baseElectContext, ergebnisart, datenGebiet, datenArt);

    this.dokumentVorlageArt = dokumentVorlageArt;

    this.zeilen = new ArrayList<>();

    this.parteiStimmenSummeQueueNummer = new LinkedList<>();
    this.parteiStimmenSummeQueueNameGruppe = new LinkedList<>();
    this.parteiStimmenSummeQueueNameWahlvorschlag = new LinkedList<>();
    this.parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag = new LinkedList<>();
    this.parteiStimmenSummeQueueKennung = new LinkedList<>();

    this.parteiStimmenSummeQueueKennungErststimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueKennungPositionErststimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlErststimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueNameGruppeErststimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueNameDirektkandidat = new LinkedList<>();
    this.parteiStimmenSummeQueueNameDirektkandidatVollstaendig = new LinkedList<>();
    this.parteiStimmenSummeQueueNameDirektkandidatVorname = new LinkedList<>();

    this.parteiStimmenSummeQueueKennungZweitstimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueKennungPositionZweitstimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlZweitstimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert = new LinkedList<>();
    this.parteiStimmenSummeQueueNameGruppeZweitstimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueNameListe = new LinkedList<>();
  }

  @Override
  public List<ErgebnisGesamtergebnisTabellarischDocumentZeile> getZeilen() {
    return zeilen;
  }

  public void removeAnzahlParteiEintraege(int anzahl) {
    // Naive Implementierung, kann sicher mit sublist verbesser werden
    for (int i = 0; i < anzahl; i++) {
      parteiStimmenSummeQueueNummer.poll();
      parteiStimmenSummeQueueNameGruppe.poll();
      parteiStimmenSummeQueueNameWahlvorschlag.poll();
      parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag.poll();
      parteiStimmenSummeQueueKennung.poll();

      parteiStimmenSummeQueueKennungErststimmen.poll();
      parteiStimmenSummeQueueKennungPositionErststimmen.poll();
      parteiStimmenSummeQueueAnzahlErststimmen.poll();
      parteiStimmenSummeQueueNameGruppeErststimmen.poll();
      parteiStimmenSummeQueueNameDirektkandidat.poll();
      parteiStimmenSummeQueueNameDirektkandidatVollstaendig.poll();
      parteiStimmenSummeQueueNameDirektkandidatVorname.poll();

      parteiStimmenSummeQueueKennungZweitstimmen.poll();
      parteiStimmenSummeQueueKennungPositionZweitstimmen.poll();
      parteiStimmenSummeQueueAnzahlZweitstimmen.poll();
      parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.poll();
      parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.poll();
      parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.poll();
      parteiStimmenSummeQueueNameGruppeZweitstimmen.poll();
      parteiStimmenSummeQueueNameListe.poll();

      if (ergebnisSummen != null) {
        ergebnisSummen.parteiStimmenQueueNummer.poll();
        ergebnisSummen.parteiStimmenQueueNameGruppe.poll();
        ergebnisSummen.parteiStimmenQueueNameWahlvorschlag.poll();
        ergebnisSummen.parteiStimmenQueueStimmzettelPositionWahlvorschlag.poll();
        ergebnisSummen.parteiStimmenQueueKennung.poll();

        ergebnisSummen.parteiStimmenQueueKennungErststimmen.poll();
        ergebnisSummen.parteiStimmenQueueKennungPositionErststimmen.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlErststimmen.poll();
        ergebnisSummen.parteiStimmenQueueNameGruppeErststimmen.poll();
        ergebnisSummen.parteiStimmenQueueNameDirektkandidat.poll();
        ergebnisSummen.parteiStimmenQueueNameDirektkandidatVollstaendig.poll();
        ergebnisSummen.parteiStimmenQueueNameDirektkandidatVorname.poll();

        ergebnisSummen.parteiStimmenQueueKennungZweitstimmen.poll();
        ergebnisSummen.parteiStimmenQueueKennungPositionZweitstimmen.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlZweitstimmen.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.poll();
        ergebnisSummen.parteiStimmenQueueNameGruppeZweitstimmen.poll();
        ergebnisSummen.parteiStimmenQueueNameListe.poll();
      }
    }

    for (ErgebnisGesamtergebnisTabellarischDocumentZeile zeile : zeilen) {
      for (int j = 0; j < anzahl; j++) {
        zeile.parteiStimmenQueueNummer.poll();
        zeile.parteiStimmenQueueNameGruppe.poll();
        zeile.parteiStimmenQueueNameWahlvorschlag.poll();
        zeile.parteiStimmenQueueStimmzettelPositionWahlvorschlag.poll();
        zeile.parteiStimmenQueueKennung.poll();

        zeile.parteiStimmenQueueKennungErststimmen.poll();
        zeile.parteiStimmenQueueKennungPositionErststimmen.poll();
        zeile.parteiStimmenQueueAnzahlErststimmen.poll();
        zeile.parteiStimmenQueueNameGruppeErststimmen.poll();
        zeile.parteiStimmenQueueNameDirektkandidat.poll();
        zeile.parteiStimmenQueueNameDirektkandidatVollstaendig.poll();
        zeile.parteiStimmenQueueNameDirektkandidatVorname.poll();

        zeile.parteiStimmenQueueKennungZweitstimmen.poll();
        zeile.parteiStimmenQueueKennungPositionZweitstimmen.poll();
        zeile.parteiStimmenQueueAnzahlZweitstimmen.poll();
        zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.poll();
        zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.poll();
        zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.poll();
        zeile.parteiStimmenQueueNameGruppeZweitstimmen.poll();
        zeile.parteiStimmenQueueNameListe.poll();
      }
    }
  }

  public void berechneSummen(List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilen) {
    if (ergebnisSummen == null) {
      ErgebnisDocumentDatenGebietDocument datenGebiet; // ELECT-13050
      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet; // ELECT-8094

      List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilenBerechenbar = filterZeilenBerechenbar(zeilen);

      if (!zeilenBerechenbar.isEmpty()) {
        ErgebnisGesamtergebnisTabellarischDocumentZeile zeileBerechenbar = zeilenBerechenbar.get(0);

        datenGebiet = zeileBerechenbar.datenGebiet;
        wahldurchfuehrungsgebiet = zeileBerechenbar.wahldurchfuehrungsgebiet;
      } else {
        datenGebiet = new ErgebnisDocumentDatenGebietDocument();
        wahldurchfuehrungsgebiet = null;
      }

      ergebnisSummen = createDocumentZeileSummen(wahldurchfuehrungsgebiet);

      if (zeilenBerechenbar.stream().allMatch(zeileBerechenbar -> Objects.equals(zeileBerechenbar.datenGebiet.nummer, datenGebiet.nummer))) {
        ergebnisSummen.datenGebiet = datenGebiet;
      }
    }

    ergebnisSummen.setSummen(zeilen);
  }

  public void berechneUeberschriftenQueue() {
    parteiStimmenSummeQueueNummer.clear();
    parteiStimmenSummeQueueNameGruppe.clear();
    parteiStimmenSummeQueueNameWahlvorschlag.clear();
    parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag.clear();
    parteiStimmenSummeQueueKennung.clear();

    parteiStimmenSummeQueueKennungErststimmen.clear();
    parteiStimmenSummeQueueKennungPositionErststimmen.clear();
    parteiStimmenSummeQueueAnzahlErststimmen.clear();
    parteiStimmenSummeQueueNameGruppeErststimmen.clear();
    parteiStimmenSummeQueueNameDirektkandidat.clear();
    parteiStimmenSummeQueueNameDirektkandidatVollstaendig.clear();
    parteiStimmenSummeQueueNameDirektkandidatVorname.clear();

    parteiStimmenSummeQueueKennungZweitstimmen.clear();
    parteiStimmenSummeQueueKennungPositionZweitstimmen.clear();
    parteiStimmenSummeQueueAnzahlZweitstimmen.clear();
    parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.clear();
    parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.clear();
    parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.clear();
    parteiStimmenSummeQueueNameGruppeZweitstimmen.clear();
    parteiStimmenSummeQueueNameListe.clear();

    if (!zeilen.isEmpty()) { // ELECT-8775
      ErgebnisGesamtergebnisTabellarischDocumentZeile ersteZeile = zeilen.get(0);

      parteiStimmenSummeQueueNummer.addAll(ersteZeile.parteiStimmenQueueNummer);
      parteiStimmenSummeQueueNameGruppe.addAll(ersteZeile.parteiStimmenQueueNameGruppe);
      parteiStimmenSummeQueueNameWahlvorschlag.addAll(ersteZeile.parteiStimmenQueueNameWahlvorschlag);
      parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag.addAll(ersteZeile.parteiStimmenQueueStimmzettelPositionWahlvorschlag);
      parteiStimmenSummeQueueKennung.addAll(ersteZeile.parteiStimmenQueueKennung);

      parteiStimmenSummeQueueKennungErststimmen.addAll(ersteZeile.parteiStimmenQueueKennungErststimmen);
      parteiStimmenSummeQueueKennungPositionErststimmen.addAll(ersteZeile.parteiStimmenQueueKennungPositionErststimmen);
      parteiStimmenSummeQueueNameGruppeErststimmen.addAll(ersteZeile.parteiStimmenQueueNameGruppeErststimmen);
      parteiStimmenSummeQueueNameDirektkandidat.addAll(ersteZeile.parteiStimmenQueueNameDirektkandidat);
      parteiStimmenSummeQueueNameDirektkandidatVollstaendig.addAll(ersteZeile.parteiStimmenQueueNameDirektkandidatVollstaendig);
      parteiStimmenSummeQueueNameDirektkandidatVorname.addAll(ersteZeile.parteiStimmenQueueNameDirektkandidatVorname);

      parteiStimmenSummeQueueKennungZweitstimmen.addAll(ersteZeile.parteiStimmenQueueKennungZweitstimmen);
      parteiStimmenSummeQueueKennungPositionZweitstimmen.addAll(ersteZeile.parteiStimmenQueueKennungPositionZweitstimmen);
      parteiStimmenSummeQueueNameGruppeZweitstimmen.addAll(ersteZeile.parteiStimmenQueueNameGruppeZweitstimmen);
      parteiStimmenSummeQueueNameListe.addAll(ersteZeile.parteiStimmenQueueNameListe);
    }

    List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilenBerechenbar = filterZeilenBerechenbar(zeilen);

    if (!zeilenBerechenbar.isEmpty()) {
      ErgebnisGesamtergebnisTabellarischDocumentZeile ersteZeile = zeilenBerechenbar.get(0);

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlErststimmen) {
        parteiStimmenSummeQueueAnzahlErststimmen.add(value == null ? null : 0L);
      }

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlZweitstimmen) {
        parteiStimmenSummeQueueAnzahlZweitstimmen.add(value == null ? null : 0L);
      }

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert) {
        parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.add(value == null ? null : 0L);
      }

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert) {
        parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.add(value == null ? null : 0L);
      }

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert) {
        parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.add(value == null ? null : 0L);
      }
    }

    for (ErgebnisGesamtergebnisTabellarischDocumentZeile zeile : zeilenBerechenbar) {
      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlErststimmen.size(); i++) {
        Long anzahlErststimmenSumme = parteiStimmenSummeQueueAnzahlErststimmen.get(i);
        Long anzahlErststimmenZeile = zeile.parteiStimmenQueueAnzahlErststimmen.get(i);

        if (anzahlErststimmenZeile != null) {
          if (anzahlErststimmenSumme == null) {
            parteiStimmenSummeQueueAnzahlErststimmen.set(i, anzahlErststimmenZeile);
          } else {
            parteiStimmenSummeQueueAnzahlErststimmen.set(i, anzahlErststimmenSumme + anzahlErststimmenZeile);
          }
        }
      }

      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlZweitstimmen.size(); i++) {
        Long anzahlZweitstimmenSumme = parteiStimmenSummeQueueAnzahlZweitstimmen.get(i);
        Long anzahlZweitstimmenZeile = zeile.parteiStimmenQueueAnzahlZweitstimmen.get(i);

        if (anzahlZweitstimmenZeile != null) {
          if (anzahlZweitstimmenSumme == null) {
            parteiStimmenSummeQueueAnzahlZweitstimmen.set(i, anzahlZweitstimmenZeile);
          } else {
            parteiStimmenSummeQueueAnzahlZweitstimmen.set(i, anzahlZweitstimmenSumme + anzahlZweitstimmenZeile);
          }
        }
      }

      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.size(); i++) {
        Long anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertSumme = parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.get(i);
        Long anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertZeile = zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.get(i);

        if (anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertZeile != null) {
          if (anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertSumme == null) {
            parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.set(i, anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertZeile);
          } else {
            parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.set(i,
                anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertSumme + anzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendertZeile);
          }
        }
      }

      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.size(); i++) {
        Long anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertSumme = parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.get(i);
        Long anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertZeile = zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.get(i);

        if (anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertZeile != null) {
          if (anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertSumme == null) {
            parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.set(i, anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertZeile);
          } else {
            parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.set(i,
                anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertSumme + anzahlStimmzettelNurEinzelnerWahlvorschlagVeraendertZeile);
          }
        }
      }

      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.size(); i++) {
        Long anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertSumme = parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.get(i);
        Long anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertZeile = zeile.parteiStimmenQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.get(i);

        if (anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertZeile != null) {
          if (anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertSumme == null) {
            parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.set(i, anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertZeile);
          } else {
            parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.set(i,
                anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertSumme + anzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiertZeile);
          }
        }
      }
    }
  }

  protected ErgebnisGesamtergebnisTabellarischDocumentZeileSummen createDocumentZeileSummen(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return new ErgebnisGesamtergebnisTabellarischDocumentZeileSummen(ergebnisart, wahldurchfuehrungsgebiet);
  }

  public ErgebnisGesamtergebnisTabellarischDocument copy() {
    return copy(dokumentVorlageArt);
  }

  public ErgebnisGesamtergebnisTabellarischDocument copy(ErgebnisGesamtergebnisTabellarischDocumentDokumentVorlageArt dokumentVorlageArt) {
    return copyTo(new ErgebnisGesamtergebnisTabellarischDocument(baseElectContext, ergebnisart, dokumentVorlageArt, datenGebiet, datenArt));
  }

  protected ErgebnisGesamtergebnisTabellarischDocument copyTo(ErgebnisGesamtergebnisTabellarischDocument target) {
    super.copyTo(target);

    for (ErgebnisGesamtergebnisTabellarischDocumentZeile zeile : zeilen) {
      target.zeilen.add(zeile.copy());
    }

    target.parteiStimmenSummeQueueNummer.addAll(parteiStimmenSummeQueueNummer);
    target.parteiStimmenSummeQueueNameGruppe.addAll(parteiStimmenSummeQueueNameGruppe);
    target.parteiStimmenSummeQueueNameWahlvorschlag.addAll(parteiStimmenSummeQueueNameWahlvorschlag);
    target.parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag.addAll(parteiStimmenSummeQueueStimmzettelPositionWahlvorschlag);
    target.parteiStimmenSummeQueueKennung.addAll(parteiStimmenSummeQueueKennung);

    target.parteiStimmenSummeQueueKennungErststimmen.addAll(parteiStimmenSummeQueueKennungErststimmen);
    target.parteiStimmenSummeQueueKennungPositionErststimmen.addAll(parteiStimmenSummeQueueKennungPositionErststimmen);
    target.parteiStimmenSummeQueueAnzahlErststimmen.addAll(parteiStimmenSummeQueueAnzahlErststimmen);
    target.parteiStimmenSummeQueueNameGruppeErststimmen.addAll(parteiStimmenSummeQueueNameGruppeErststimmen);
    target.parteiStimmenSummeQueueNameDirektkandidat.addAll(parteiStimmenSummeQueueNameDirektkandidat);
    target.parteiStimmenSummeQueueNameDirektkandidatVollstaendig.addAll(parteiStimmenSummeQueueNameDirektkandidatVollstaendig);
    target.parteiStimmenSummeQueueNameDirektkandidatVorname.addAll(parteiStimmenSummeQueueNameDirektkandidatVorname);

    target.parteiStimmenSummeQueueKennungZweitstimmen.addAll(parteiStimmenSummeQueueKennungZweitstimmen);
    target.parteiStimmenSummeQueueKennungPositionZweitstimmen.addAll(parteiStimmenSummeQueueKennungPositionZweitstimmen);
    target.parteiStimmenSummeQueueAnzahlZweitstimmen.addAll(parteiStimmenSummeQueueAnzahlZweitstimmen);
    target.parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert.addAll(parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagUnveraendert);
    target.parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert.addAll(parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagVeraendert);
    target.parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert.addAll(parteiStimmenSummeQueueAnzahlStimmzettelNurEinzelnerWahlvorschlagPanaschiert);
    target.parteiStimmenSummeQueueNameGruppeZweitstimmen.addAll(parteiStimmenSummeQueueNameGruppeZweitstimmen);
    target.parteiStimmenSummeQueueNameListe.addAll(parteiStimmenSummeQueueNameListe);

    if (ergebnisSummen != null) {
      target.ergebnisSummen = ergebnisSummen.copy();
    }

    return target;
  }
}
