
package de.ivu.elect.business.stimmeingabe.control;

import static de.ivu.elect.jee.entity.EntityUtil.castTo;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

import javax.annotation.Nullable;
import javax.inject.Inject;

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

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppeEigenschaften;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.KandidaturStimmzettelPersonendaten;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.kandidatur.entity.ListenkandidaturStimmzettelPosition;
import de.ivu.elect.business.kandidatur.entity.WaehlerBenannteKandidaturen;
import de.ivu.elect.business.stimmeingabe.boundary.DefaultStimmeingabeKopfzahlLabelGenerator;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingangsart;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.ZwischensummeEingabe;
import de.ivu.elect.business.stimmen.boundary.DirektstimmeLabelGenerator;
import de.ivu.elect.business.stimmen.boundary.GruppeStimmeLabelGenerator;
import de.ivu.elect.business.stimmen.boundary.ListenkandidaturstimmeLabelGenerator;
import de.ivu.elect.business.stimmen.boundary.ListenstimmeLabelGenerator;
import de.ivu.elect.business.stimmen.boundary.StimmenartLabelGenerator;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;
import de.ivu.elect.business.wahlvorschlag.entity.Direktkandidat;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStimmzettelPosition;
import de.ivu.elect.jee.faces.Messages;

public abstract class AbstractStimmeingabeErfassenLabelGenerator implements Serializable, StimmeingabeKopfzahlErfassenLabelGenerator, StimmeingabeGruppeStimmenErfassenLabelGenerator {

  private static final long serialVersionUID = 1L;

  protected static final Logger LOG = LoggerFactory.getLogger(AbstractStimmeingabeErfassenLabelGenerator.class);

  @Inject
  private transient Messages messages;

  @Inject
  private transient SystemGruppeEigenschaften systemGruppeEigenschaften;

  @Inject
  private transient StimmenartLabelGenerator stimmenartLabelGenerator;

  @Inject
  private transient GruppeStimmeLabelGenerator gruppeStimmeLabelGenerator;

  @Inject
  private transient DefaultStimmeingabeKopfzahlLabelGenerator stimmeingabeKopfzahlLabelGenerator;

  protected AbstractStimmeingabeErfassenLabelGenerator() {
    super();
  }

  @Override
  public String getGruppeStimmenStimmeingabeKennungFortlaufend(EntityAufStimmzettelDaten entityAufStimmzettelDaten, @Nullable Long stimmeingabeIndexOneBased, Stimmeingabe stimmeingabe,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null) {
      return getGruppeStimmenKennungFortlaufend(entityAufStimmzettelDaten, stimmeingabeIndexOneBased, stimmeingabe.getGruppeImGebiet(), stimmeingabe.getErgebniseingangsart(),
          stimmeingabe.getStimmenart(), gruppenImGebiet);
    }

    return "";
  }

  @Override
  public String getGruppeStimmenKennungFortlaufend(EntityAufStimmzettelDaten entityAufStimmzettelDaten, @Nullable Long positionFortlaufend, GruppeImGebiet gruppeImGebiet,
      WahlartErgebnisart ergebnisart, Stimmenart stimmenart, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (positionFortlaufend != null && gruppeImGebiet != null) {
      if (gruppenImGebiet.contains(gruppeImGebiet)) {
        if (isStimmenartDirektstimme(stimmenart)) {
          return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeKennungFortlaufend(entityAufStimmzettelDaten, positionFortlaufend, gruppeImGebiet);
        }

        if (isStimmenartListenstimme(stimmenart)) {
          return getListenstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeKennungFortlaufend(entityAufStimmzettelDaten, positionFortlaufend, gruppeImGebiet);
        }
      }

      LOG.warn("Zur GruppeImGebiet [{}] und Stimmenart [{}] kann keine fortlaufende Kennung mit Position {} generiert werden", gruppeImGebiet, stimmenart, positionFortlaufend);
    }

    return "";
  }

  @Override
  public String getGruppeStimmenStimmeingabeKennung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null) {
      return getGruppeStimmenKennung(entityAufStimmzettelDaten, stimmeingabe.getGruppeImGebiet(), stimmeingabe.getErgebniseingangsart(), stimmeingabe.getStimmenart(), gruppenImGebiet);
    }

    return "";
  }

  @Override
  public String getGruppeStimmenStimmeingabeBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null) {
      return getGruppeStimmenBezeichnung(entityAufStimmzettelDaten, stimmeingabe.getGruppeImGebiet(), stimmeingabe.getErgebniseingangsart(), stimmeingabe.getStimmenart(), gruppenImGebiet);
    }

    return "";
  }

  @Override
  public String getGruppeStimmenStimmeingabeTooltip(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    return "";
  }

  @Override
  public String getGruppeStimmenKennung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, WahlartErgebnisart ergebnisart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (gruppeImGebiet != null) {
      if (gruppeImGebiet.isSystemGruppe()) {
        if (isSystemGruppeUngueltige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlUngueltigeGesamtKennung(gruppeImGebiet, ergebnisart);
        }

        if (isSystemGruppeGueltige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlGueltigeGesamtKennung(gruppeImGebiet, ergebnisart);
        }

        if (isSystemGruppeUebrige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlUebrigeGesamtKennung(gruppeImGebiet, ergebnisart);
        }

        if (isSystemGruppeWaehler(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlAbgegebeneGesamtKennung(gruppeImGebiet, ergebnisart);
        }
      } else if (gruppenImGebiet.contains(gruppeImGebiet)) {
        return getGruppeStimmeLabelGenerator().formatStimmenAnzahlGueltigeKennung(entityAufStimmzettelDaten, gruppeImGebiet, ergebnisart, gruppenImGebiet);
      }
    }

    LOG.warn("Zur GruppeImGebiet [{}] kann keine Kennung generiert werden", gruppeImGebiet);

    return "";
  }

  @Override
  public String getGruppeStimmenKennung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, WahlartErgebnisart ergebnisart, Stimmenart stimmenart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmenart != null && gruppeImGebiet != null) {
      if (gruppeImGebiet.isSystemGruppe()) {
        if (isSystemGruppeUngueltige(gruppeImGebiet)) {
          if (isStimmenartDirektstimme(stimmenart)) {
            return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlUngueltigeGesamtKennung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimme(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlUngueltigeGesamtKennung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimmeUnbestimmt(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlUnbestimmteGesamtKennung(gruppeImGebiet, gruppenImGebiet);
          }
        }

        if (isSystemGruppeGueltige(gruppeImGebiet)) {
          if (isStimmenartDirektstimme(stimmenart)) {
            return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeGesamtKennung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimme(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeGesamtKennung(gruppeImGebiet, gruppenImGebiet);
          }
        }

        if (isSystemGruppeUebrige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlUebrigeStimmenartKennung(gruppeImGebiet, ergebnisart, stimmenart);
        }

        if (isSystemGruppeWaehler(gruppeImGebiet)) {
          if (isStimmenartDirektstimme(stimmenart)) {
            return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlAbgegebeneGesamtKennung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimme(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlAbgegebeneGesamtKennung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
          }
        }
      } else if (gruppenImGebiet.contains(gruppeImGebiet)) {
        if (isStimmenartDirektstimme(stimmenart)) {
          return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeKennung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
        }

        if (isStimmenartListenstimme(stimmenart)) {
          return getListenstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeKennung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
        }
      }
    }

    LOG.warn("Zur GruppeImGebiet [{}] und Stimmenart [{}] kann keine Kennung generiert werden", gruppeImGebiet, stimmenart);

    return "";
  }

  @Override
  public String getGruppeStimmenBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, WahlartErgebnisart ergebnisart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (gruppeImGebiet != null) {
      if (gruppeImGebiet.isSystemGruppe()) {
        if (isSystemGruppeUngueltige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlUngueltigeGesamtBezeichnung(gruppeImGebiet, ergebnisart);
        }
        if (isSystemGruppeGueltige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlGueltigeGesamtBezeichnung(gruppeImGebiet, ergebnisart);
        }

        if (isSystemGruppeUebrige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlUebrigeGesamtBezeichnung(gruppeImGebiet, ergebnisart);
        }

        if (isSystemGruppeWaehler(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlAbgegebeneGesamtBezeichnung(gruppeImGebiet, ergebnisart);
        }
      } else if (gruppenImGebiet.contains(gruppeImGebiet)) {
        return getGruppeStimmeLabelGenerator().getWahlvorschlagStimmzettelKurzname(entityAufStimmzettelDaten, gruppeImGebiet);
      }
    }

    LOG.warn("Zur GruppeImGebiet [{}] kann keine Bezeichnung generiert werden", gruppeImGebiet);

    return "";
  }

  @Override
  public String getGruppeStimmenBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, WahlartErgebnisart ergebnisart, Stimmenart stimmenart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (gruppeImGebiet != null && stimmenart != null) {
      if (gruppeImGebiet.isSystemGruppe()) {
        if (isSystemGruppeUngueltige(gruppeImGebiet)) {
          if (isStimmenartDirektstimme(stimmenart)) {
            return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlUngueltigeGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimme(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlUngueltigeGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimmeUnbestimmt(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlUnbestimmteGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }
        }

        if (isSystemGruppeGueltige(gruppeImGebiet)) {
          if (isStimmenartDirektstimme(stimmenart)) {
            return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimme(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimmeUnbestimmt(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlUnbestimmteGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }
        }

        if (isSystemGruppeWaehler(gruppeImGebiet)) {
          if (isStimmenartDirektstimme(stimmenart)) {
            return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlAbgegebeneGesamtBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimme(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlAbgegebeneGesamtBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
          }

          if (isStimmenartListenstimmeUnbestimmt(stimmenart)) {
            return getListenstimmeLabelGenerator().formatListenstimmeAnzahlUnbestimmteGesamtBezeichnung(gruppeImGebiet, gruppenImGebiet);
          }
        }

        if (isSystemGruppeUebrige(gruppeImGebiet)) {
          return getGruppeStimmeLabelGenerator().formatStimmenAnzahlUebrigeStimmenartBezeichnung(gruppeImGebiet, ergebnisart, stimmenart);
        }
      } else if (gruppenImGebiet.contains(gruppeImGebiet)) {
        if (isStimmenartDirektstimme(stimmenart)) {
          return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
        }

        if (isStimmenartListenstimme(stimmenart)) {
          return getListenstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
        }
      }
    }

    LOG.warn("Zur GruppeImGebiet [{}] und Stimmenart [{}] kann keine Bezeichnung generiert werden", gruppeImGebiet, stimmenart);

    return "";
  }

  @Override
  public boolean isGruppeStimmenStimmeingabeGruppeBezeichnungRendered() {
    return false;
  }

  @Override
  public String getGruppeStimmenStimmeingabeGruppeBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null) {
      return getGruppeStimmenStimmeingabeGruppeBezeichnung(entityAufStimmzettelDaten, stimmeingabe.getGruppeImGebiet(), stimmeingabe.getStimmenart(), gruppenImGebiet);
    }

    return "";
  }

  protected String getGruppeStimmenStimmeingabeGruppeBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, Stimmenart stimmenart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmenart != null && gruppeImGebiet != null) {
      if (gruppeImGebiet.isSystemGruppe()) {
        return "";
      } else if (gruppenImGebiet.contains(gruppeImGebiet)) {
        if (isStimmenartDirektstimme(stimmenart)) {
          return getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeGruppeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
        }

        if (isStimmenartListenstimme(stimmenart)) {
          return getListenstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeGruppeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
        }
      }
    }

    LOG.warn("Zur GruppeImGebiet [{}] und Stimmenart [{}] kann keine Gruppe Bezeichnung generiert werden", gruppeImGebiet, stimmenart);

    return "";
  }

  public String getListenkandidaturStimmenStimmeingabeKennung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null) {
      return getListenkandidaturstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeKennung(entityAufStimmzettelDaten,
          getWahlvorschlagStimmzettelPosition(entityAufStimmzettelDaten, stimmeingabe.getGruppeImGebiet(), gruppenImGebiet), stimmeingabe.getListenkandidatur());
    }

    return "";
  }

  public String getListenkandidaturStimmenStimmeingabeBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null && stimmeingabe.hasListenkandidatur()) {
      return getListenkandidaturstimmeLabelGenerator().getListenkandidaturStimmzettelName(entityAufStimmzettelDaten, stimmeingabe.getListenkandidatur()).getName();
    }

    return "";
  }

  public String getListenkandidaturStimmenKennung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, WahlartErgebnisart ergebnisart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (gruppeImGebiet != null) {
      return getListenkandidaturstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeGruppeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
    }

    LOG.warn("Zur GruppeImGebiet [{}] kann keine Gruppe Kennung generiert werden", gruppeImGebiet);

    return "";
  }

  public String getListenkandidaturStimmenBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet, WahlartErgebnisart ergebnisart,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (gruppeImGebiet != null) {
      return getListenkandidaturstimmeLabelGenerator().formatListenstimmeAnzahlGueltigeGruppeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
    }

    LOG.warn("Zur GruppeImGebiet [{}] kann keine Gruppe Bezeichnung generiert werden", gruppeImGebiet);

    return "";
  }

  protected SystemGruppeEigenschaften getSystemGruppeEigenschaften() {
    return systemGruppeEigenschaften;
  }

  protected StimmenartLabelGenerator getStimmenartLabelGenerator() {
    return stimmenartLabelGenerator;
  }

  protected GruppeStimmeLabelGenerator getGruppeStimmeLabelGenerator() {
    return gruppeStimmeLabelGenerator;
  }

  protected DefaultStimmeingabeKopfzahlLabelGenerator getStimmeingabeKopfzahlLabelGenerator() {
    return stimmeingabeKopfzahlLabelGenerator;
  }

  protected DirektstimmeLabelGenerator getDirektstimmeLabelGenerator() {
    return getGruppeStimmeLabelGenerator().getDirektstimmeLabelGenerator();
  }

  protected ListenstimmeLabelGenerator getListenstimmeLabelGenerator() {
    return getGruppeStimmeLabelGenerator().getListenstimmeLabelGenerator();
  }

  protected ListenkandidaturstimmeLabelGenerator getListenkandidaturstimmeLabelGenerator() {
    return getListenstimmeLabelGenerator().getListenkandidaturstimmeLabelGenerator();
  }

  @Override
  public String getKopfzahlKennung(GruppeImGebiet gruppeImGebiet, Ergebniseingangsart ergebniseingangsart, Stimmenart stimmenart) {
    return getStimmeingabeKopfzahlLabelGenerator().getKopfzahlKennung(gruppeImGebiet, stimmenart, ergebniseingangsart);
  }

  @Override
  public String getKopfzahlBezeichnung(GruppeImGebiet gruppeImGebiet, Ergebniseingangsart ergebniseingangsart, Stimmenart stimmenart) {
    return getStimmeingabeKopfzahlLabelGenerator().getKopfzahlBezeichnung(gruppeImGebiet, ergebniseingangsart, stimmenart);
  }

  @Override
  public String getKopfzahlKennung(@Nullable GruppeImGebiet gruppeImGebiet, Collection<GruppeImGebiet> gruppenImGebiet) {
    return getStimmeingabeKopfzahlLabelGenerator().getKopfzahlKennung(gruppeImGebiet, gruppenImGebiet);
  }

  @Override
  public String getKopfzahlBezeichnung(@Nullable GruppeImGebiet gruppeImGebiet, Collection<GruppeImGebiet> gruppenImGebiet) {
    return getStimmeingabeKopfzahlLabelGenerator().getKopfzahlBezeichnung(gruppeImGebiet, gruppenImGebiet);
  }

  @Override
  public String getKopfzahlStimmeingabeKennung(@Nullable Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    return getStimmeingabeKopfzahlLabelGenerator().getKopfzahlStimmeingabeKennung(stimmeingabe, gruppenImGebiet);
  }

  @Override
  public String getKopfzahlStimmeingabeBezeichnung(@Nullable Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    return getStimmeingabeKopfzahlLabelGenerator().getKopfzahlStimmeingabeBezeichnung(stimmeingabe, gruppenImGebiet);
  }

  @Override
  @Nullable
  public WahlvorschlagStimmzettelPosition getWahlvorschlagStimmzettelPosition(EntityAufStimmzettelDaten entityAufStimmzettelDaten, GruppeImGebiet gruppeImGebiet,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    return getGruppeStimmeLabelGenerator().getWahlvorschlagStimmzettelPosition(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);
  }

  @Nullable
  public ListenkandidaturStimmzettelPosition getListenkandidaturStimmzettelPosition(EntityAufStimmzettelDaten entityAufStimmzettelDaten, @Nullable Stimmeingabe stimmeingabe,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null && stimmeingabe.hasListenkandidatur()) {
      // NOTE, dass bereits STIMMZETTELPOSITIONEN ins WAS importiert werden; diese können LÜCKEN enthalten, die zu erhalten sind!
      return getListenkandidaturstimmeLabelGenerator().getListenkandidaturStimmzettelPosition(entityAufStimmzettelDaten, stimmeingabe.getListenkandidatur());
    }

    return null;
  }

  public KandidaturStimmzettelPersonendaten getListenkandidaturStimmzettelName(EntityAufStimmzettelDaten entityAufStimmzettelDaten, @Nullable Stimmeingabe stimmeingabe,
      Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null && stimmeingabe.hasListenkandidatur()) {
      return getListenkandidaturstimmeLabelGenerator().getListenkandidaturStimmzettelName(entityAufStimmzettelDaten, stimmeingabe.getListenkandidatur());
    }

    return KandidaturStimmzettelPersonendaten.EMPTY;
  }

  protected boolean isSystemGruppeWaehler(GruppeImGebiet gruppeImGebiet) {
    return gruppeImGebiet != null && isSystemGruppeWaehler(gruppeImGebiet.getGruppe());
  }

  private boolean isSystemGruppeWaehler(Gruppe gruppe) {
    return equalsSystemGruppe(gruppe, SystemGruppe.WAEHLER);
  }

  protected boolean isSystemGruppeGueltige(GruppeImGebiet gruppeImGebiet) {
    return gruppeImGebiet != null && isSystemGruppeGueltige(gruppeImGebiet.getGruppe());
  }

  protected boolean isSystemGruppeGueltige(Gruppe gruppe) {
    return equalsSystemGruppe(gruppe, SystemGruppe.GUELTIGE);
  }

  protected boolean isSystemGruppeUngueltige(GruppeImGebiet gruppeImGebiet) {
    return gruppeImGebiet != null && isSystemGruppeUngueltige(gruppeImGebiet.getGruppe());
  }

  protected boolean isSystemGruppeUngueltige(Gruppe gruppe) {
    return equalsSystemGruppe(gruppe, SystemGruppe.UNGUELTIGE);
  }

  protected boolean isSystemGruppeUebrige(GruppeImGebiet gruppeImGebiet) {
    return gruppeImGebiet != null && isSystemGruppeUebrige(gruppeImGebiet.getGruppe());
  }

  protected boolean isSystemGruppeUebrige(Gruppe gruppe) {
    return equalsSystemGruppe(gruppe, SystemGruppe.UEBRIGE);
  }

  private boolean equalsSystemGruppe(Gruppe gruppe, SystemGruppe expected) {
    return gruppe != null && expected.equalsGruppe(gruppe, getSystemGruppeEigenschaften());
  }

  protected boolean isStimmeingabeZwischensumme(Stimmeingabe stimmeingabe, long summenIndex) {
    if (stimmeingabe != null && stimmeingabe.isZwischensummeEingabe()) {
      return Objects.equals(castTo(stimmeingabe, ZwischensummeEingabe.class).getSummenIndex(), summenIndex);
    }

    return false;
  }

  protected boolean isStimmeingabeDirektstimme(Stimmeingabe stimmeingabe) {
    return stimmeingabe != null && isStimmenartDirektstimme(stimmeingabe.getStimmenart());
  }

  protected boolean isStimmeingabeListenstimme(Stimmeingabe stimmeingabe) {
    return stimmeingabe != null && isStimmenartListenstimme(stimmeingabe.getStimmenart());
  }

  protected boolean isStimmeingabeReferendumOption(Stimmeingabe stimmeingabe) {
    return stimmeingabe != null && stimmeingabe.hasReferendumOption() && isStimmenartReferendumStimme(stimmeingabe.getStimmenart());
  }

  protected boolean isGruppeImGebietFuerWaehlerBenannteKandidaturen(GruppeImGebiet gruppeImGebiet) {
    if (gruppeImGebiet != null) {
      Gruppe gruppe = gruppeImGebiet.getGruppe();

      return WaehlerBenannteKandidaturen.isWaehlerBenannterDirektkandidatGruppe(gruppe) || WaehlerBenannteKandidaturen.isWaehlerBenannteListeGruppe(gruppe);
    }

    return false;
  }

  @Override
  public String getStimmenartName(Gebiet gebiet, Stimmenart stimmenart) {
    if (isStimmenartDirektstimme(stimmenart)) {
      return getStimmenartLabelGenerator().getDirektstimmeBezeichnungPlural(gebiet);
    }

    if (isStimmenartListenstimme(stimmenart)) {
      return getStimmenartLabelGenerator().getListenstimmeBezeichnungPlural(gebiet);
    }

    if (isStimmenartReferendumStimme(stimmenart)) {
      return getStimmenartLabelGenerator().getReferendumStimmeBezeichnungPlural(gebiet);
    }

    return "";
  }

  protected boolean isStimmenartDirektstimme(Stimmenart stimmenart) {
    return stimmenart != null && stimmenart.isDirektstimme();
  }

  protected boolean isStimmenartListenstimme(Stimmenart stimmenart) {
    return stimmenart != null && (stimmenart.isListenstimme() || stimmenart.isListenstimmeAbzuziehen()); // ELECT-4030
  }

  protected boolean isStimmenartListenstimmeUnbestimmt(Stimmenart stimmenart) {
    return stimmenart != null && stimmenart.isListenstimmeUnbestimmt();
  }

  protected boolean isStimmenartReferendumStimme(Stimmenart stimmenart) {
    return stimmenart != null && stimmenart.isReferendumStimmenart(); // ELECTBB-236
  }

  @Override
  public String getGruppeDirektstimmenStimmeingabeBezeichnung(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet,
      Supplier<Map<Gruppe, Collection<Wahlvorschlag>>> wahlvorschlaege) {
    if (stimmeingabe == null || !stimmeingabe.hasGruppeImGebiet() || !gruppenImGebiet.contains(stimmeingabe.getGruppeImGebiet())) {
      return "";
    }

    GruppeImGebiet gruppeImGebiet = stimmeingabe.getGruppeImGebiet();

    if (gruppeImGebiet.isSystemGruppe() && (isSystemGruppeGueltige(gruppeImGebiet) || isSystemGruppeUngueltige(gruppeImGebiet))) {
      return getGruppeStimmenBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, stimmeingabe.getErgebniseingangsart(), stimmeingabe.getStimmenart(), gruppenImGebiet);
    }

    Direktkandidat direktkandidat = gruppeImGebiet.getDirektkandidatAufStimmzettelInUebergeordneterGebietshierarchie(wahlvorschlaege);

    if (direktkandidat == null) {
      return "";
    }

    String result = getDirektstimmeLabelGenerator().formatDirektstimmeAnzahlGueltigeBezeichnung(entityAufStimmzettelDaten, gruppeImGebiet, gruppenImGebiet);

    // NOTE, dass hier die bisherige Anzeige auf der Erfassungsmaske beibehalten wird.
    if (!direktkandidat.isEinzelbewerber()) {
      // TODO Name der Partei einheitlich bestimmen, bspw. formatDirektstimmeAnzahlGueltigeGruppeBezeichnung.
      result += " (" + direktkandidat.getGruppeImGebiet().getKurznameAufGebiet() + ")";
    }

    return result;
  }

  @Override
  public String getGruppeDirektstimmenStimmeingabeTooltip(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet,
      Supplier<Map<Gruppe, Collection<Wahlvorschlag>>> wahlvorschlaege) {
    if (stimmeingabe != null) {
      GruppeImGebiet gruppeImGebiet = stimmeingabe.getGruppeImGebiet();

      if (gruppeImGebiet != null && gruppenImGebiet.contains(gruppeImGebiet)) {
        Direktkandidat direktkandidat = gruppeImGebiet.getDirektkandidatAufStimmzettelInUebergeordneterGebietshierarchie(wahlvorschlaege);

        if (direktkandidat != null) {
          Direktkandidatur direktkandidatur = direktkandidat.getDirektkandidatur();

          if (WaehlerBenannteKandidaturen.isWaehlerBenannteDirektkandidaturSonstige(getMessages(), direktkandidatur)) {
            return WaehlerBenannteKandidaturen.formatWaehlerBenannteDirektkandidaturSonstigeBeschreibung(getMessages(), direktkandidatur);
          }
        }
      }
    }

    return "";
  }

  public String getListenkandidaturStimmenStimmeingabeTooltip(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Stimmeingabe stimmeingabe, Collection<GruppeImGebiet> gruppenImGebiet) {
    if (stimmeingabe != null) {
      Listenkandidatur listenkandidatur = stimmeingabe.getListenkandidatur();

      if (WaehlerBenannteKandidaturen.isWaehlerBenannteListenkandidaturSonstige(getMessages(), listenkandidatur)) {
        return WaehlerBenannteKandidaturen.formatWaehlerBenannteListenkandidaturSonstigeBeschreibung(getMessages(), listenkandidatur);
      }
    }

    return "";
  }

  protected String getMessage(String msgKey, Object... params) {
    return getMessages().getMessageForMessageKey(msgKey, params);
  }

  protected String getMessage(Enum< ? > enumValue, Object... params) {
    return getMessages().lokalisiere(enumValue, params);
  }

  protected Messages getMessages() {
    return messages;
  }
}
