
package de.ivu.elect.was.exchange.wahl;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

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

import de.ivu.elect.business.WusFeaturesAktiviert;
import de.ivu.elect.business.dokumente.entity.DokumentVorlage;
import de.ivu.elect.business.ergebnis.boundary.SitzeFactory;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Ergebnisart;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.ergebnis.entity.Sitze;
import de.ivu.elect.business.ergebnis.entity.Stimmen;
import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.fremdkandidatur.entity.Fremdkandidatur;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPolygonPoint;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.GebietsartTK;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsgruppierung;
import de.ivu.elect.business.gruppe.boundary.GruppeFactory;
import de.ivu.elect.business.gruppe.boundary.PolitischeGruppeFactory;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppeArt;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppeEigenschaften;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietFactory;
import de.ivu.elect.business.gruppeimgebiet.control.GruppeImGebietReihenfolgeVorsortierer;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietStatus;
import de.ivu.elect.business.image.entity.Bild;
import de.ivu.elect.business.internet.entity.InternetSeite;
import de.ivu.elect.business.kandidatenportal.entity.WvpWarnung;
import de.ivu.elect.business.kandidatur.boundary.DirektkandidaturFactory;
import de.ivu.elect.business.kandidatur.boundary.ErsatzkandidaturFactory;
import de.ivu.elect.business.kandidatur.boundary.ListenkandidaturFactory;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.Ersatzkandidatur;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.KandidaturQuelle;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.kandidatur.entity.ListenkandidaturArt;
import de.ivu.elect.business.kandidatur.entity.Waehlbarkeit;
import de.ivu.elect.business.person.boundary.PersonendatenVerknuepfer;
import de.ivu.elect.business.person.entity.PersonenVerknuepfung;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.pruefung.boundary.ZulassungPrueferDAOFactory;
import de.ivu.elect.business.staat.boundary.StaatenGruppeFactory;
import de.ivu.elect.business.staat.entity.StaatenGruppe;
import de.ivu.elect.business.staat.entity.StaatenGruppeTyp;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiKonfiguration;
import de.ivu.elect.business.stimmzettel.boundary.EntityAufStimmzettelDatenStimmzettelPositionBerechnung;
import de.ivu.elect.business.stimmzettel.entity.Stimmzettel;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelGueltigkeit;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelKopfdatum;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelStatus;
import de.ivu.elect.business.veranstaltung.entity.Veranstaltung;
import de.ivu.elect.business.wahl.boundary.WahlterminFactory;
import de.ivu.elect.business.wahl.control.Wahldaten;
import de.ivu.elect.business.wahl.entity.WahlParameter;
import de.ivu.elect.business.wahl.entity.WahlParameterLoader;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.business.wahl.entity.Wahlgang;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.business.wahlausschuss.boundary.WahlausschussmitgliedFactory;
import de.ivu.elect.business.wahlausschuss.entity.WahlausschussEntschaedigung;
import de.ivu.elect.business.wahlausschuss.entity.Wahlausschussmitglied;
import de.ivu.elect.business.wahlausschuss.entity.Wahlausschussrolle;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlauf;
import de.ivu.elect.business.wahlrechtspruefung.entity.Pruefkriterium;
import de.ivu.elect.business.wahlrechtspruefung.entity.Wahlrechtspruefung;
import de.ivu.elect.business.wahlvorschlag.entity.Direktkandidat;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.Listenverbindung;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOption;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStatus;
import de.ivu.elect.business.wahlvorschlagsperson.boundary.WahlvorschlagsPersonFactory;
import de.ivu.elect.business.wahlvorschlagsperson.entity.WahlvorschlagsPerson;
import de.ivu.elect.business.wahlvorschlagsperson.entity.WahlvorschlagsPersonTyp;
import de.ivu.elect.core.exchange.internet.mapper.InternetMapper;
import de.ivu.elect.core.exchange.mapper.StimmzettelMapper;
import de.ivu.elect.core.exchange.mapper.WahlInternExternMapperUtil;
import de.ivu.elect.core.exchange.wahlbeteiligung.mapper.WahlbeteiligungMapper;
import de.ivu.elect.exchange.EntityMapper;
import de.ivu.elect.exchange.dokumente.mapper.DokumentVorlageMapper;
import de.ivu.elect.exchange.gebietsbaum.mapper.GebietMapper;
import de.ivu.elect.exchange.gebietsbaum.mapper.GebietPolygonMapperUtil;
import de.ivu.elect.exchange.image.mapper.BildMapper;
import de.ivu.elect.exchange.person.mapper.PersonMapper;
import de.ivu.elect.exchange.person.mapper.TeilnahmeMapper;
import de.ivu.elect.exchange.staat.mapper.StaatMapper;
import de.ivu.elect.exchange.veranstaltung.VeranstaltungMapper;
import de.ivu.elect.exchange.wahl.WahlKonfigurationMapper;
import de.ivu.elect.exchange.wahl.mapper.WahlParameterMapper;
import de.ivu.elect.interfaces.core.GebietReferenz;
import de.ivu.elect.interfaces.core.GewaehltStatus;
import de.ivu.elect.interfaces.core.GruppeImGebietReferenz;
import de.ivu.elect.interfaces.core.GruppeReferenz;
import de.ivu.elect.interfaces.core.KandidaturReferenz;
import de.ivu.elect.interfaces.core.KandidaturVerknuepfung;
import de.ivu.elect.interfaces.core.Person;
import de.ivu.elect.interfaces.core.PersonReferenz;
import de.ivu.elect.interfaces.core.VeranstaltungReferenz;
import de.ivu.elect.interfaces.core.VerknuepfungsArt;
import de.ivu.elect.interfaces.core.VerknuepfungsGrundlage;
import de.ivu.elect.interfaces.core.VerknuepfungsStatus;
import de.ivu.elect.interfaces.core.Wahl;
import de.ivu.elect.interfaces.core.WahlvorschlagReferenz;
import de.ivu.elect.interfaces.core.konfiguration.Gebietsarteigenschaft;
import de.ivu.elect.interfaces.core.zulassungspruefung.PruefkriteriumReferenz;
import de.ivu.elect.interfaces.core.zulassungspruefung.Zulassungspruefung;
import de.ivu.elect.interfaces.gebietgeometrie.GebietGeometrie;
import de.ivu.elect.interfaces.wes.StimmzettelImGebiet;
import de.ivu.elect.interfaces.wvp.Kandidatenportal;
import de.ivu.elect.jee.entity.customdata.EmptyCustomData;
import de.ivu.elect.was.exchange.stimmeingabe.StimmeingabePlausiKonfigurationMapper;
import de.ivu.elect.wus.exchange.wahlrechtspruefung.mapper.ZulassungspruefungMapper;
import de.ivu.elect.wvp.exchange.mapper.KandidatenportalMapper;

public abstract class AbstractWahlExternInternMapper<Wahlobject extends de.ivu.elect.business.wahl.entity.Wahl> {

  public static final String FORMAT_NAME = "file.format.wahl.was";

  @Inject
  protected transient WahlInternExternMapperUtil wahlInternExternMapperUtil;

  @Inject
  protected transient WahlterminFactory wahlterminFactory;

  @Inject
  protected transient DirektkandidaturFactory direktkandidaturFactory;

  @Inject
  protected transient ListenkandidaturFactory listenkandidaturFactory;

  @Inject
  protected transient ErsatzkandidaturFactory ersatzkandidaturFactory;

  @Inject
  protected transient GruppeImGebietFactory gruppeImGebietFactory;

  @Inject
  protected transient GruppeFactory gruppeFactory;

  @Inject
  protected transient SitzeFactory sitzeFactory;

  @Inject
  protected transient PolitischeGruppeFactory politischeGruppeFactory;

  @Inject
  protected transient WahlvorschlagsPersonFactory wahlvorschlagsPersonFactory;

  @Inject
  protected transient WahlausschussmitgliedFactory wahlausschussmitgliedFactory;

  @Inject
  protected transient StaatenGruppeFactory staatenGruppeFactory;

  @Inject
  protected transient SystemGruppeEigenschaften systemGruppeEigenschaften;

  @Inject
  protected transient WahlParameterLoader wahlParameterLoader;

  @Inject
  protected transient ZulassungPrueferDAOFactory zulassungPrueferDAOFactory;

  @Inject
  protected transient StimmzettelFormatter stimmzettelFormatter;

  @Inject
  protected transient EntityAufStimmzettelDatenStimmzettelPositionBerechnung entityAufStimmzettelDatenStimmzettelPositionBerechnung;

  @Inject
  protected transient GruppeImGebietReihenfolgeVorsortierer gruppeImGebietReihenfolgeVorsortierer;

  @Inject
  protected transient WahlKonfigurationMapper wahlKonfigurationMapper;

  @Inject
  protected transient GebietPolygonMapperUtil gebietPolygonMapperUtil;

  @Inject
  protected transient PersonendatenVerknuepfer personendatenVerknuepfer;

  @Inject
  protected transient WahlbeteiligungMapper wahlbeteiligungMapper;

  @Inject
  protected transient InternetMapper internetMapper;

  @Inject
  protected transient StimmeingabePlausiKonfigurationMapper stimmeingabePlausiKonfigurationMapper;

  @Inject
  protected transient GebietMapper gebietMapper;

  @Inject
  protected transient BildMapper bildMapper;

  @Inject
  protected transient WahlParameterMapper wahlParameterMapper;

  @Inject
  protected transient StaatMapper staatMapper;

  @Inject
  protected transient PersonMapper personMapper;

  @Inject
  protected transient VeranstaltungMapper veranstaltungMapper;

  @Inject
  protected transient TeilnahmeMapper teilnahmeMapper;

  @Inject
  protected transient WusFeaturesAktiviert wusFeaturesAktiviert;

  @Inject
  protected transient DokumentVorlageMapper dokumentVorlageMapper;

  @Inject
  protected transient StimmzettelMapper stimmzettelMapper;

  @Inject
  protected transient ZulassungspruefungMapper zulassungspruefungMapper;

  @Inject
  protected transient KandidatenportalMapper kandidatenportalMapper;

  public AbstractWahlExternInternMapper() {
    super();
  }

  public Wahldaten mappe(Wahl wahlExtern) {
    Wahlobject wahlIntern = createEmptyWahlobject();
    wahlIntern.setCustomDataXml(wahlExtern.getCustomData());

    Wahltermin wahlterminIntern = wahlterminFactory.create();
    wahlIntern.setWahltermin(wahlterminIntern);

    Wahlart wahlartIntern = null;

    if (wahlExtern.getWahlKonfiguration() != null) {
      wahlartIntern = wahlExtern.getWahlKonfiguration().getWahlarten().stream().filter(wahlart -> wahlart != null && wahlart.getName() != null && wahlart.getName().equals(wahlExtern.getWahlart()))
          .findFirst().map(wahlart -> wahlKonfigurationMapper.mappe(wahlart)).orElse(null);
    }

    wahlterminIntern.setWahldatum(wahlExtern.getWahldatum());
    if (wahlExtern.getWahlterminNummer() != null) {
      wahlterminIntern.setNummer(wahlExtern.getWahlterminNummer());
    }

    if (wahlartIntern == null) {
      wahlartIntern = new Wahlart();
      wahlartIntern.setName(wahlExtern.getWahlart());
    }

    wahlIntern.setWahlart(wahlartIntern);

    mapWahl(wahlExtern, wahlIntern);

    Map<GebietReferenz, Gebiet> gebieteInternPerReferenzExtern = mapGebiete(wahlExtern);
    Map<GruppeReferenz, Gruppe> gruppenInternPerReferenzExtern = mapGruppen(wahlExtern, wahlIntern);
    Map<GruppeImGebietReferenz, GruppeImGebiet> gruppenImGebietInternPerReferenzExtern = mapGruppenImGebiet(wahlExtern, gebieteInternPerReferenzExtern, gruppenInternPerReferenzExtern);

    Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern = mapVeranstaltungen(wahlExtern, gebieteInternPerReferenzExtern);

    Map<WahlvorschlagReferenz, Wahlvorschlag> wahlvorschlagInternPerReferenzExtern = mapWahlvorschlaege(wahlExtern, gruppenImGebietInternPerReferenzExtern);

    Map<PersonReferenz, Kandidatur> kandidaturInternPerReferenzExtern = new HashMap<>();

    for (Entry<PersonReferenz, Kandidatur> entry : mapKandidaturen(wahlExtern, wahlvorschlagInternPerReferenzExtern, veranstaltungInternPerReferenzExtern).entrySet()) {
      Kandidatur kandidaturIntern = entry.getValue();

      if (isKandidaturInternZuUebernehmen(kandidaturIntern)) { // ELECT-7262
        kandidaturInternPerReferenzExtern.put(entry.getKey(), kandidaturIntern);
      }
    }

    Map<Ergebnisart, List<Stimmen>> stimmenNachErgebnisart = mapStimmen(wahlExtern, gruppenImGebietInternPerReferenzExtern);

    List<Gewaehlt> gewaehlteVorperiode = mapGewaehlteVorperiode(wahlExtern, kandidaturInternPerReferenzExtern);

    List<Sitze> sitzeVorperiode = mapSitzeVorperiode(wahlExtern, gruppenImGebietInternPerReferenzExtern);

    Map<PersonReferenz, WahlvorschlagsPerson> wahlvorschlagsPersonInternPerReferenzExtern = mapWahlvorschlagsPersonen(wahlExtern, wahlvorschlagInternPerReferenzExtern,
        veranstaltungInternPerReferenzExtern);

    Map<PersonReferenz, Wahlausschussmitglied> wahlausschussmitgliederInternPerReferenzExtern = mapWahlausschussmitglieder(wahlExtern, gebieteInternPerReferenzExtern, gruppenInternPerReferenzExtern,
        veranstaltungInternPerReferenzExtern);
    List<WahlausschussEntschaedigung> wahlausschussEntschaedigungen = mapWahlausschussEntschaedigung(wahlExtern, wahlIntern);

    List<StaatenGruppe> staatenGruppen = mapStaatenGruppen(wahlIntern, wahlExtern.getStaatenGruppen());

    List<Gebietsgruppierung> gebietsgruppierungen = mapGebietsgruppierungen(wahlIntern, gebieteInternPerReferenzExtern, wahlExtern.getGebietsgruppierungen());

    List<GebietPolygonPoint> gebietPolygonPoints = mapGebietPolygonPoints(wahlExtern, gebieteInternPerReferenzExtern);

    Map<PersonReferenz, Fremdkandidatur> fremdkandidaturenInternPerReferenzExtern = mapFremdkandidaturen(wahlExtern, veranstaltungInternPerReferenzExtern);

    List<InternetSeite> internetSeiten = mapInternetSeiten(wahlExtern);

    if (wahlExtern.getWahlKonfiguration() != null) {
      Map<GebietsartTK, Gebietsart> gebietsartTKGebietsartIntern = GebietsartTK
          .mappeGebietsartNachTK(gebieteInternPerReferenzExtern.values().stream().map(Gebiet::getGebietsart).collect(Collectors.toSet()));

      for (Gebietsarteigenschaft gebietsarteigenschaft : wahlExtern.getWahlKonfiguration().getGebietsarteigenschaften()) {
        if (gebietsarteigenschaft.getWahlartName() != null && gebietsarteigenschaft.getWahlartName().equals(wahlartIntern.getName())) {

          de.ivu.elect.business.gebietsbaum.entity.Gebietsarteigenschaft gebietsarteigenschaftIntern = wahlKonfigurationMapper.mappe(gebietsarteigenschaft);
          GebietsartTK gebietsartTK = new GebietsartTK(gebietsarteigenschaft.getGebietsartName());

          Gebietsart gebietsart = gebietsartTKGebietsartIntern.computeIfAbsent(gebietsartTK, x -> wahlExtern.getWahlKonfiguration().getGebietsarten().stream()
              .filter(gae -> gebietsartTK.getName().equals(gae.getName())).findFirst().map(gebietsartExtern -> wahlKonfigurationMapper.mappe(gebietsartExtern)).orElse(null));

          if (gebietsart != null) {
            gebietsarteigenschaftIntern.setWahlart(wahlartIntern);
            gebietsarteigenschaftIntern.setGebietsart(gebietsart);
          }
        }
      }
    }

    List<WahlbeteiligungVerlauf> wahlbeteiligungVerlaeufe = mapWahlbeteiligungVerlaeufe(wahlExtern);

    List<StimmeingabePlausiKonfiguration> stimmeingabePlausiKonfigurationen = mapStimmeingabePlausiKonfigurationen(wahlExtern, wahlIntern);

    // Stimmzettelerfassung
    List<Stimmzettel> stimmzettel = mapStimmzettel(wahlExtern, gebieteInternPerReferenzExtern);
    List<StimmzettelKopfdatum> stimmzettelKopfdaten = mapStimmzettelKopfdaten(wahlExtern, gebieteInternPerReferenzExtern, gruppenInternPerReferenzExtern);

    // Zulassungsprüfung
    Map<PruefkriteriumReferenz, Pruefkriterium> pruefkriteriumInternPerReferenzExtern = mapPruefkriterien(wahlExtern);
    List<Wahlrechtspruefung> wahlrechtspruefungen = mapWahlrechtspruefungen(wahlExtern, pruefkriteriumInternPerReferenzExtern, wahlvorschlagInternPerReferenzExtern, kandidaturInternPerReferenzExtern);

    // Kandidatenportal
    List<WvpWarnung> wvpWarnungen = mapWvpWarnungen(wahlExtern, wahlvorschlagInternPerReferenzExtern, kandidaturInternPerReferenzExtern, wahlvorschlagsPersonInternPerReferenzExtern);

    // ELECT-11327, Verknuepfungen erst NACH dem Mappen aller Personendaten mappen, cf. WahlInternExternMapper#mapPersonenVerknuepfungen!!!
    List<PersonenVerknuepfung> personenVerknuepfungen = mapPersonenVerknuepfungen(wahlExtern, kandidaturInternPerReferenzExtern, wahlvorschlagsPersonInternPerReferenzExtern,
        wahlausschussmitgliederInternPerReferenzExtern, fremdkandidaturenInternPerReferenzExtern);

    return new Wahldaten<>(wahlIntern, () -> new ArrayList<>(gebieteInternPerReferenzExtern.values()), () -> new ArrayList<>(gruppenInternPerReferenzExtern.values()),
        () -> new ArrayList<>(gruppenImGebietInternPerReferenzExtern.values()), () -> new ArrayList<>(wahlvorschlagInternPerReferenzExtern.values()),
        () -> new ArrayList<>(kandidaturInternPerReferenzExtern.values()), () -> personenVerknuepfungen, ergebnisart -> stimmenNachErgebnisart.getOrDefault(ergebnisart, emptyList()),
        () -> gewaehlteVorperiode, () -> sitzeVorperiode, () -> new ArrayList<>(wahlvorschlagsPersonInternPerReferenzExtern.values()),
        () -> new ArrayList<>(wahlausschussmitgliederInternPerReferenzExtern.values()), () -> wahlausschussEntschaedigungen, () -> staatenGruppen, () -> gebietsgruppierungen,
        systemGruppeEigenschaften, wahlParameterLoader, zulassungPrueferDAOFactory.createZulassungPruefer(), stimmzettelFormatter, entityAufStimmzettelDatenStimmzettelPositionBerechnung,
        gruppeImGebietReihenfolgeVorsortierer, () -> gebietPolygonPoints, () -> new ArrayList<>(fremdkandidaturenInternPerReferenzExtern.values()), () -> internetSeiten,
        () -> wahlbeteiligungVerlaeufe, () -> stimmeingabePlausiKonfigurationen, () -> new ArrayList<>(veranstaltungInternPerReferenzExtern.values()), () -> stimmzettel, () -> stimmzettelKopfdaten,
        () -> new ArrayList<>(pruefkriteriumInternPerReferenzExtern.values()), () -> wahlrechtspruefungen, () -> wvpWarnungen);
  }

  private Map<PruefkriteriumReferenz, Pruefkriterium> mapPruefkriterien(Wahl wahlExtern) {
    Zulassungspruefung zulassungspruefung = wahlExtern.getZulassungspruefung();

    if (isWusFeaturesEnabled() && zulassungspruefung != null) {
      List<de.ivu.elect.interfaces.core.zulassungspruefung.Pruefkriterium> pruefkriterienExtern = zulassungspruefung.getPruefkriterien();

      if (pruefkriterienExtern != null) {
        return pruefkriterienExtern.stream().collect(toMap(de.ivu.elect.interfaces.core.zulassungspruefung.Pruefkriterium::getPruefkriteriumReferenz, zulassungspruefungMapper::intern));
      }
    }

    return emptyMap();
  }

  private List<Wahlrechtspruefung> mapWahlrechtspruefungen(Wahl wahlExtern, Map<PruefkriteriumReferenz, Pruefkriterium> pruefkriteriumInternPerReferenzExtern,
      Map<WahlvorschlagReferenz, Wahlvorschlag> wahlvorschlagInternPerReferenzExtern, Map<PersonReferenz, Kandidatur> kandidaturInternPerReferenzExtern) {
    Zulassungspruefung zulassungspruefung = wahlExtern.getZulassungspruefung();

    if (isWusFeaturesEnabled() && zulassungspruefung != null) {
      List<de.ivu.elect.interfaces.core.zulassungspruefung.Wahlrechtspruefung> wahlrechtspruefungenExtern = zulassungspruefung.getWahlrechtspruefungen();

      if (wahlrechtspruefungenExtern != null) {
        Map<KandidaturReferenz, Kandidatur> kandidaturInternPerKandidaturReferenzExtern = mapKandidaturenNachReferenz(kandidaturInternPerReferenzExtern.values());

        return wahlrechtspruefungenExtern.stream()
            .map(extern -> zulassungspruefungMapper.intern(extern, pruefkriteriumInternPerReferenzExtern, wahlvorschlagInternPerReferenzExtern, kandidaturInternPerKandidaturReferenzExtern))
            .collect(toList());
      }
    }

    return emptyList();
  }

  // ELECT-11642
  private List<WvpWarnung> mapWvpWarnungen(Wahl wahlExtern, Map<WahlvorschlagReferenz, Wahlvorschlag> wahlvorschlagInternPerReferenzExtern,
      Map<PersonReferenz, Kandidatur> kandidaturInternPerReferenzExtern, Map<PersonReferenz, WahlvorschlagsPerson> wahlvorschlagsPersonInternPerReferenzExtern) {
    Kandidatenportal kandidatenportal = wahlExtern.getKandidatenportal();

    if (isWusFeaturesEnabled() && kandidatenportal != null) {
      List<de.ivu.elect.interfaces.wvp.WvpWarnung> wvpWarnungenExtern = kandidatenportal.getWvpWarnungen();

      if (wvpWarnungenExtern != null) {
        Map<KandidaturReferenz, Kandidatur> kandidaturInternPerKandidaturReferenzExtern = mapKandidaturenNachReferenz(kandidaturInternPerReferenzExtern.values());

        return wvpWarnungenExtern.stream()
            .map(extern -> kandidatenportalMapper.intern(extern, wahlvorschlagInternPerReferenzExtern, kandidaturInternPerKandidaturReferenzExtern, wahlvorschlagsPersonInternPerReferenzExtern))
            .collect(toList());
      }
    }

    return emptyList();
  }

  private List<StimmzettelKopfdatum> mapStimmzettelKopfdaten(Wahl wahlExtern, Map<GebietReferenz, Gebiet> gebieteIntern, Map<GruppeReferenz, Gruppe> gruppenIntern) {
    List<StimmzettelKopfdatum> result = new ArrayList<>();

    if (wahlExtern.getStimmzettelerfassung() != null && wahlExtern.getStimmzettelerfassung().getStimmzettelImGebiet() != null) {
      for (StimmzettelImGebiet stimmzettelImGebiet : wahlExtern.getStimmzettelerfassung().getStimmzettelImGebiet()) {
        if (stimmzettelImGebiet.getGebietReferenz() != null && gebieteIntern.get(stimmzettelImGebiet.getGebietReferenz()) != null) {
          Gebiet gebiet = gebieteIntern.get(stimmzettelImGebiet.getGebietReferenz());

          for (de.ivu.elect.interfaces.wes.StimmzettelKopfdatum stimmzettelKopfdatumExtern : stimmzettelImGebiet.getStimmzettelKopfdaten()) {
            if (stimmzettelKopfdatumExtern.getGruppeReferenz() == null || gruppenIntern.get(stimmzettelKopfdatumExtern.getGruppeReferenz()) != null) {
              StimmzettelKopfdatum stimmzettelKopfdatum = new StimmzettelKopfdatum();
              result.add(stimmzettelKopfdatum);

              if (stimmzettelKopfdatumExtern.getGruppeReferenz() != null) {
                stimmzettelKopfdatum.setGruppe(gruppenIntern.get(stimmzettelKopfdatumExtern.getGruppeReferenz()));
              }

              stimmzettelKopfdatum.setSchluessel(stimmzettelKopfdatumExtern.getSchluessel());
              stimmzettelKopfdatum.setWert(stimmzettelKopfdatumExtern.getWert());
              stimmzettelKopfdatum.setGebiet(gebiet);
            }
          }
        }
      }
    }

    return result;
  }

  protected List<Stimmzettel> mapStimmzettel(Wahl wahlExtern, Map<GebietReferenz, Gebiet> gebieteIntern) {
    List<Stimmzettel> result = new ArrayList<>();

    if (wahlExtern.getStimmzettelerfassung() != null && wahlExtern.getStimmzettelerfassung().getStimmzettelImGebiet() != null) {
      for (StimmzettelImGebiet stimmzettelImGebiet : wahlExtern.getStimmzettelerfassung().getStimmzettelImGebiet()) {
        if (stimmzettelImGebiet.getGebietReferenz() != null && gebieteIntern.get(stimmzettelImGebiet.getGebietReferenz()) != null) {
          Gebiet gebiet = gebieteIntern.get(stimmzettelImGebiet.getGebietReferenz());

          for (de.ivu.elect.interfaces.wes.Stimmzettel stimmzettelExtern : stimmzettelImGebiet.getErfassteStimmzettel()) {
            Stimmzettel stimmzettel = stimmzettelMapper.mappe(stimmzettelExtern);
            stimmzettel.setGebiet(gebiet);
            result.add(stimmzettel);
          }
        }
      }
    }

    return result;
  }

  protected StimmzettelGueltigkeit mappeStimmzettelGueltigkeit(String gueltigkeit) {
    if (isNotBlank(gueltigkeit)) {
      try {
        return StimmzettelGueltigkeit.valueOf(gueltigkeit);
      } catch (Exception ignored) {
      }
    }

    return StimmzettelGueltigkeit.UNBEKANNT;
  }

  protected StimmzettelStatus mappeStimmzettelStatus(String status) {
    if (isNotBlank(status)) {
      try {
        return StimmzettelStatus.valueOf(status);
      } catch (Exception ignored) {
      }
    }

    return StimmzettelStatus.INITIAL;
  }

  private Map<VeranstaltungReferenz, Veranstaltung> mapVeranstaltungen(Wahl wahlExtern, Map<GebietReferenz, Gebiet> gebieteIntern) {
    return veranstaltungMapper.mapVeranstaltungen(wahlExtern.getVeranstaltungList(), gebieteIntern);
  }

  private List<StimmeingabePlausiKonfiguration> mapStimmeingabePlausiKonfigurationen(Wahl wahlExtern, Wahlobject wahlIntern) {
    return stimmeingabePlausiKonfigurationMapper.mappe(wahlExtern.getStimmeingabePlausiKonfigurationen(), wahlIntern);
  }

  private List<WahlbeteiligungVerlauf> mapWahlbeteiligungVerlaeufe(Wahl wahlExtern) {
    if (wahlExtern.getWahlbeteiligungExchange() == null) {
      return emptyList();
    }
    return wahlbeteiligungMapper.mappe(wahlExtern.getWahlbeteiligungExchange());

  }

  private List<InternetSeite> mapInternetSeiten(Wahl wahlExtern) {
    if (wahlExtern.getInternetKonfiguration() == null) {
      return emptyList();
    }

    return internetMapper.mappe(wahlExtern.getInternetKonfiguration()).getInternetSeiten();
  }

  protected void mapWahl(Wahl wahlExtern, Wahlobject wahlIntern) {
    wahlIntern.setFarbe(wahlExtern.getFarbe());
    wahlIntern.setName(wahlExtern.getName());
    wahlIntern.setKurzname(wahlExtern.getKurzname());
    wahlIntern.setKennzeichen(wahlExtern.getKennzeichen());

    if (wahlExtern.getAnzahlStimmzettel() != null) { // Abwärtskompatibilität
      wahlIntern.setAnzahlStimmzettel(wahlExtern.getAnzahlStimmzettel());
    }

    wahlIntern.setQuorumProzenthuerde(wahlExtern.getQuorum());

    if (wahlExtern.getUnterstuetzerErfassbar() != null) {
      wahlIntern.setUnterstuetzerErfassbar(wahlExtern.getUnterstuetzerErfassbar());
    }

    if (wahlExtern.getAnzahlUnterstuetzerEintragungsliste() != null) {
      wahlIntern.setAnzahlUnterstuetzerPerEintragungsliste(wahlExtern.getAnzahlUnterstuetzerEintragungsliste());
    }

    if (wahlExtern.getWahlgang() != null) {
      wahlIntern.setWahlgang(mappe(wahlExtern.getWahlgang()));
    }
  }

  protected static Wahlgang mappe(de.ivu.elect.interfaces.core.Wahlgang wahlgang) {
    return Wahlgang.valueOf(wahlgang.name());
  }

  protected abstract Map<PersonReferenz, Fremdkandidatur> mapFremdkandidaturen(Wahl wahlExtern, Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern);

  private List<GebietPolygonPoint> mapGebietPolygonPoints(Wahl wahlExtern, Map<GebietReferenz, Gebiet> gebieteIntern) {
    GebietGeometrie gebietGeometrie = wahlExtern.getGebietGeometrie();

    if (gebietGeometrie == null) {
      return emptyList();
    }

    return gebietGeometrie.getGebietPolygonPoints().stream().map(p -> gebietPolygonMapperUtil.mappe(p, gebieteIntern)).collect(Collectors.toList());
  }

  protected List<WahlausschussEntschaedigung> mapWahlausschussEntschaedigung(Wahl wahlExtern, Wahlobject wahlIntern) {
    List<WahlausschussEntschaedigung> result = new ArrayList<>();

    for (de.ivu.elect.interfaces.core.WahlausschussEntschaedigung wahlausschussEntschaedigungExtern : wahlExtern.getWahlausschussEntschaedigungen()) {
      WahlausschussEntschaedigung wahlausschussEntschaedigungIntern = new WahlausschussEntschaedigung();
      wahlausschussEntschaedigungIntern.setBetrag(wahlausschussEntschaedigungExtern.getBetrag());
      wahlausschussEntschaedigungIntern.setWahl(wahlIntern);
      wahlausschussEntschaedigungIntern.setWahlausschussrolle(mappe(wahlausschussEntschaedigungExtern.getRolle()));
      wahlausschussEntschaedigungIntern.setWaehrungAlsIsoCode(wahlausschussEntschaedigungExtern.getWaehrungAlsIsoCode());
      result.add(wahlausschussEntschaedigungIntern);
    }

    return result;
  }

  protected List<StaatenGruppe> mapStaatenGruppen(Wahlobject wahlIntern, List<de.ivu.elect.interfaces.core.StaatenGruppe> staatenGruppenExtern) {
    List<StaatenGruppe> staatenGruppenIntern = new ArrayList<>();

    for (de.ivu.elect.interfaces.core.StaatenGruppe staatenGruppeExtern : staatenGruppenExtern) {
      StaatenGruppe staatenGruppeIntern = staatenGruppeFactory.create();

      staatenGruppeIntern.setWahl(wahlIntern);
      staatenGruppeIntern.setWahltermin(wahlIntern.getWahltermin());
      staatenGruppeIntern.setBezeichnung(staatenGruppeExtern.getBezeichnung());
      staatenGruppeIntern.setStaatenGruppeTyp(StaatenGruppeTyp.valueOf(staatenGruppeExtern.getStaatenGruppeTyp().name()));
      staatenGruppeIntern.setCustomDataXml(staatenGruppeExtern.getCustomData());

      for (de.ivu.elect.interfaces.core.Staat staatExtern : staatenGruppeExtern.getStaaten()) {
        staatenGruppeIntern.addStaat(staatMapper.intern(staatExtern));
      }

      staatenGruppenIntern.add(staatenGruppeIntern);
    }

    return staatenGruppenIntern;
  }

  private List<Gebietsgruppierung> mapGebietsgruppierungen(Wahlobject wahlIntern, Map<GebietReferenz, Gebiet> gebieteIntern,
      List<de.ivu.elect.interfaces.core.Gebietsgruppierung> gebietsgruppierungenExtern) {
    List<Gebietsgruppierung> gebietsgruppierungenIntern = new ArrayList<>();

    for (de.ivu.elect.interfaces.core.Gebietsgruppierung gebietsgruppierungExtern : gebietsgruppierungenExtern) {
      Gebietsgruppierung gebietsgruppierungIntern = new Gebietsgruppierung();

      gebietsgruppierungIntern.setWahl(wahlIntern);
      gebietsgruppierungIntern.setWahltermin(wahlIntern.getWahltermin());
      gebietsgruppierungIntern.setName(gebietsgruppierungExtern.getName());
      gebietsgruppierungIntern.setGebietsgruppierungArt(gebietsgruppierungExtern.getGebietsgruppierungArt());
      gebietsgruppierungIntern.setPosition(gebietsgruppierungExtern.getPosition());

      for (de.ivu.elect.interfaces.core.GebietReferenz gebietExtern : gebietsgruppierungExtern.getGebiete()) {
        Gebiet gebiet = gebieteIntern.get(gebietExtern);

        if (gebiet != null) {
          gebietsgruppierungIntern.addGebiet(gebiet);
        }
      }

      gebietsgruppierungenIntern.add(gebietsgruppierungIntern);
    }

    return gebietsgruppierungenIntern;
  }

  // ELECT-11163
  private Map<PersonReferenz, WahlvorschlagsPerson> mapWahlvorschlagsPersonen(Wahl wahlExtern, Map<WahlvorschlagReferenz, Wahlvorschlag> wahlvorschlagInternPerReferenzExtern,
      Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    List<de.ivu.elect.interfaces.core.WahlvorschlagsPerson> wahlvorschlagsPersonenExtern = wahlExtern.getWahlvorschlagsPersonen();

    if (isWusFeaturesEnabled() && wahlvorschlagsPersonenExtern != null) {
      return wahlvorschlagsPersonenExtern.stream() //
          .collect(toMap(wahlInternExternMapperUtil::mappePersonendatenZuReferenz,
              wahlvorschlagsPersonExtern -> mapWahlvorschlagsPerson(wahlvorschlagsPersonExtern, wahlvorschlagInternPerReferenzExtern, veranstaltungInternPerReferenzExtern)));
    }

    return emptyMap();
  }

  private WahlvorschlagsPerson mapWahlvorschlagsPerson(de.ivu.elect.interfaces.core.WahlvorschlagsPerson wahlvorschlagsPersonExtern,
      Map<WahlvorschlagReferenz, Wahlvorschlag> wahlvorschlagInternPerReferenzExtern, Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    WahlvorschlagsPerson wahlvorschlagsPersonIntern = wahlvorschlagsPersonFactory.create();

    mapPersonendaten(wahlvorschlagsPersonExtern, wahlvorschlagsPersonIntern, veranstaltungInternPerReferenzExtern);

    wahlvorschlagsPersonIntern.setWahlvorschlag(wahlvorschlagInternPerReferenzExtern.get(wahlvorschlagsPersonExtern.getWahlvorschlagReferenz()));
    wahlvorschlagsPersonIntern.setWahlvorschlagsPersonTyp(WahlvorschlagsPersonTyp.valueOf(wahlvorschlagsPersonExtern.getWahlvorschlagsPersonTyp().name()));

    wahlvorschlagsPersonIntern.setDatumUnterschrift(wahlvorschlagsPersonExtern.getDatumUnterschrift());
    wahlvorschlagsPersonIntern.setEingangssequenznummer(wahlvorschlagsPersonExtern.getEingangssequenznummer());
    wahlvorschlagsPersonIntern.setErstellungErfasser(wahlvorschlagsPersonExtern.getErstellungErfasser());
    wahlvorschlagsPersonIntern.setErstellungZeitpunkt(wahlvorschlagsPersonExtern.getErstellungZeitpunkt());

    // Unterstützer werden nicht exportiert, daher werden deren komplexe Attribute auch nicht gemappt...
    // wahlvorschlagsPersonIntern.setEintragungslisteEintrag(wahlvorschlagsPersonExtern.getEintragungslisteEintrag());
    // wahlvorschlagsPersonIntern.setErstellungOrt(wahlvorschlagsPersonExtern.getErstellungOrt());

    return wahlvorschlagsPersonIntern;
  }

  private Map<PersonReferenz, Wahlausschussmitglied> mapWahlausschussmitglieder(Wahl wahlExtern, Map<GebietReferenz, Gebiet> gebieteIntern, Map<GruppeReferenz, Gruppe> gruppenIntern,
      Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    LinkedHashMap<PersonReferenz, Wahlausschussmitglied> result = new LinkedHashMap<>();

    // TODO Methode mal "irgendwann" aufräumen...

    Map<Long, Wahlausschussmitglied> wahlausschussmitgliedInternPerIdInDatei = new HashMap<>();
    Map<de.ivu.elect.interfaces.core.Wahlausschussmitglied, Wahlausschussmitglied> internNachExtern = new HashMap<>();

    Map<PersonReferenz, Wahlausschussmitglied> alleMitglieder = new HashMap<>();

    for (de.ivu.elect.interfaces.core.Wahlausschussmitglied wahlausschussmitgliedExtern : wahlExtern.getWahlausschussmitglieder()) {
      Wahlausschussmitglied wahlausschussmitgliedIntern = wahlausschussmitgliedFactory.create();
      mapPersonendaten(wahlausschussmitgliedExtern, wahlausschussmitgliedIntern, veranstaltungInternPerReferenzExtern);

      wahlausschussmitgliedIntern.setGebiet(gebieteIntern.get(wahlausschussmitgliedExtern.getGebiet()));

      if (wahlausschussmitgliedExtern.getPolitischeGruppe() != null) {
        wahlausschussmitgliedIntern.setPolitischeGruppe(gruppenIntern.get(wahlausschussmitgliedExtern.getPolitischeGruppe()).castTo(PolitischeGruppe.class).getEntity());
      }

      wahlausschussmitgliedIntern.setWahlausschussrolle(mappe(wahlausschussmitgliedExtern.getWahlausschussrolle()));

      alleMitglieder.put(wahlInternExternMapperUtil.mappePersonendatenZuReferenz(wahlausschussmitgliedExtern), wahlausschussmitgliedIntern);

      internNachExtern.put(wahlausschussmitgliedExtern, wahlausschussmitgliedIntern);

      Long idInDatei = EntityMapper.createIdInDatei(wahlausschussmitgliedExtern);

      if (idInDatei != null) {
        wahlausschussmitgliedInternPerIdInDatei.put(idInDatei, wahlausschussmitgliedIntern);
      }
    }

    if (wahlausschussmitgliedInternPerIdInDatei.isEmpty()) {
      return alleMitglieder;
    }

    // Vetreter setzen
    for (de.ivu.elect.interfaces.core.Wahlausschussmitglied wahlausschussmitgliedExtern : wahlExtern.getWahlausschussmitglieder()) {
      Long verterterIdInDatei = wahlausschussmitgliedExtern.getVerterterId();

      if (verterterIdInDatei != null) {
        internNachExtern.get(wahlausschussmitgliedExtern).setVertreter(wahlausschussmitgliedInternPerIdInDatei.get(verterterIdInDatei));
      }
    }

    // TODO Comparator?
    // erst alle ohne Vertreter - wegen CASCADE persist Geschichte...
    for (Entry<PersonReferenz, Wahlausschussmitglied> entry : alleMitglieder.entrySet()) {
      Wahlausschussmitglied wahlausschussmitglied = entry.getValue();

      if (wahlausschussmitglied != null && wahlausschussmitglied.getVertreter() == null) {
        result.put(entry.getKey(), wahlausschussmitglied);
      }
    }

    // dann alle mit Vertreter - wegen CASCADE persist Geschichte...
    for (Entry<PersonReferenz, Wahlausschussmitglied> entry : alleMitglieder.entrySet()) {
      Wahlausschussmitglied wahlausschussmitglied = entry.getValue();

      if (wahlausschussmitglied != null && wahlausschussmitglied.getVertreter() != null) {
        result.put(entry.getKey(), wahlausschussmitglied);
      }
    }

    return result;
  }

  protected abstract Wahlobject createEmptyWahlobject();

  private Map<Ergebnisart, List<Stimmen>> mapStimmen(Wahl wahlExtern, Map<GruppeImGebietReferenz, GruppeImGebiet> gruppenImGebietInternPerReferenzExtern) {

    Map<Ergebnisart, List<Stimmen>> result = new EnumMap<>(Ergebnisart.class);
    Map<Ergebnisart, Ergebnis> ergebnisNachArt = new EnumMap<>(Ergebnisart.class);

    for (de.ivu.elect.interfaces.core.GruppeImGebiet gruppeImGebietExtern : wahlExtern.getGruppenImGebiet()) {
      GruppeImGebiet gruppeImGebietIntern = gruppenImGebietInternPerReferenzExtern.get(gruppeImGebietExtern.getGruppeImGebietReferenz());

      for (de.ivu.elect.interfaces.core.Stimmen stimmenExtern : gruppeImGebietExtern.getStimmergebnis()) {
        Stimmen stimmenIntern = erstelleStimmen(bestimmeAnzahl(stimmenExtern), mappe(stimmenExtern.getStimmenart()), gruppeImGebietIntern);
        if (stimmenIntern != null) {
          Ergebnisart ergebnisart = bestimmeErgebnisart(stimmenExtern);
          stimmenIntern.setErgebnis(ergebnisNachArt.computeIfAbsent(ergebnisart, x -> erzeugeErgebnis(ergebnisart)));
          result.computeIfAbsent(ergebnisart, x -> new ArrayList<>()).add(stimmenIntern);
        }
      }
    }

    return result;
  }

  private Ergebnis erzeugeErgebnis(Ergebnisart ergebnisart) {
    Ergebnis result = new Ergebnis();
    result.setErgebnisart(ergebnisart);
    return result;
  }

  private Ergebnisart bestimmeErgebnisart(de.ivu.elect.interfaces.core.Stimmen stimmenExtern) {
    // Abwärtskompatibilität
    if (stimmenExtern.getErgebnisart() == null) {
      return Ergebnisart.VORPERIODE;
    }
    return mappe(stimmenExtern.getErgebnisart());
  }

  private Long bestimmeAnzahl(de.ivu.elect.interfaces.core.Stimmen stimmenExtern) {
    if (stimmenExtern.getAnzahl() != null) {
      return stimmenExtern.getAnzahl();
    }
    // Abwärtskompatibilität
    return stimmenExtern.getAnzahlVorperiode();
  }

  @Nullable
  private Stimmen erstelleStimmen(Long anzahlStimmen, Stimmenart stimmenart, GruppeImGebiet gruppeImGebietIntern) {
    if (anzahlStimmen == null || anzahlStimmen.equals(0L)) {
      return null;
    }
    Stimmen stimmen = new Stimmen();
    stimmen.setGruppe(gruppeImGebietIntern.getGruppe());
    stimmen.setGebiet(gruppeImGebietIntern.getGebiet());
    stimmen.setStimmenart(stimmenart);
    stimmen.setAnzahl(anzahlStimmen);
    return stimmen;
  }

  private List<Sitze> mapSitzeVorperiode(Wahl wahlExtern, Map<GruppeImGebietReferenz, GruppeImGebiet> gruppenImGebietIntern) {
    ArrayList<Sitze> result = new ArrayList<>();

    for (de.ivu.elect.interfaces.core.Sitze sitzeExtern : wahlExtern.getSitzeVorperiode()) {
      GruppeImGebiet gruppeImGebietIntern = gruppenImGebietIntern.get(sitzeExtern.getGruppeImGebietReferenz());
      Sitze sitzeIntern = erstelleSitze(sitzeExtern, gruppeImGebietIntern);
      result.add(sitzeIntern);
    }

    return result;
  }

  private Sitze erstelleSitze(de.ivu.elect.interfaces.core.Sitze sitzeExtern, GruppeImGebiet gruppeImGebietIntern) {
    Sitze sitze = sitzeFactory.create();
    sitze.setGruppe(gruppeImGebietIntern.getGruppe());
    sitze.setGebiet(gruppeImGebietIntern.getGebiet());
    sitze.setAnzahl(sitzeExtern.getAnzahl());
    sitze.setAnzahlAnspruch(sitzeExtern.getAnzahlAnspruch());
    sitze.setCustomDataXml(sitzeExtern.getCustomData());

    return sitze;
  }

  private List<Gewaehlt> mapGewaehlteVorperiode(Wahl wahlExtern, Map<PersonReferenz, Kandidatur> kandidaturInternPerReferenzExtern) {
    List<Gewaehlt> result = new ArrayList<>();

    Map<KandidaturReferenz, Kandidatur> kandidaturInternPerKandidaturReferenzExtern = mapKandidaturenNachReferenz(kandidaturInternPerReferenzExtern.values());

    for (de.ivu.elect.interfaces.core.Gewaehlt gewaehltExtern : wahlExtern.getGewaehltVorperiode()) {
      KandidaturReferenz kandidaturReferenzExtern = gewaehltExtern.getKandidaturReferenz();

      if (kandidaturInternPerKandidaturReferenzExtern.containsKey(kandidaturReferenzExtern)) {
        result.add(erstelleGewaehlt(gewaehltExtern, kandidaturInternPerKandidaturReferenzExtern.get(kandidaturReferenzExtern)));
      }
    }

    return result;
  }

  private Gewaehlt erstelleGewaehlt(de.ivu.elect.interfaces.core.Gewaehlt gewaehltExtern, Kandidatur kandidaturIntern) {
    Gewaehlt gewaehlt = new Gewaehlt(EmptyCustomData.INSTANCE);
    gewaehlt.setKandidatur(kandidaturIntern);
    gewaehlt.setGewaehltStatus(mappe(gewaehltExtern.getGewaehltStatus()));
    gewaehlt.setRang(gewaehltExtern.getRang());
    gewaehlt.setCustomDataXml(gewaehltExtern.getCustomData());

    return gewaehlt;
  }

  protected de.ivu.elect.business.ergebnis.entity.GewaehltStatus mappe(GewaehltStatus gewaehltStatus) {
    return de.ivu.elect.business.ergebnis.entity.GewaehltStatus.valueOf(gewaehltStatus.name());
  }

  protected List<PersonenVerknuepfung> mapPersonenVerknuepfungen(Wahl wahlExtern, Map<PersonReferenz, Kandidatur> kandidaturInternPerReferenzExtern,
      Map<PersonReferenz, WahlvorschlagsPerson> wahlvorschlagsPersonInternPerReferenzExtern, Map<PersonReferenz, Wahlausschussmitglied> wahlausschussmitgliedInternPerReferenzExtern,
      Map<PersonReferenz, Fremdkandidatur> fremdkandidaturenInternPerReferenzExtern) {
    List<PersonenVerknuepfung> result = new ArrayList<>();

    Map<PersonReferenz, Personendaten> personendatenInternPerReferenzExtern = new HashMap<>();

    // ELECT-11327
    personendatenInternPerReferenzExtern.putAll(kandidaturInternPerReferenzExtern);
    personendatenInternPerReferenzExtern.putAll(wahlvorschlagsPersonInternPerReferenzExtern);
    personendatenInternPerReferenzExtern.putAll(wahlausschussmitgliedInternPerReferenzExtern);
    personendatenInternPerReferenzExtern.putAll(fremdkandidaturenInternPerReferenzExtern);

    Map<KandidaturReferenz, Kandidatur> kandidaturInternPerKandidaturReferenzExtern = mapKandidaturenNachReferenz(kandidaturInternPerReferenzExtern.values());

    for (KandidaturVerknuepfung kandidaturVerknuepfung : wahlExtern.getKandidaturVerknuepfungen()) {
      if (kandidaturVerknuepfung != null) {
        Personendaten person1 = null;
        Personendaten person2 = null;

        PersonReferenz person1Referenz = kandidaturVerknuepfung.getPerson1Referenz();
        PersonReferenz person2Referenz = kandidaturVerknuepfung.getPerson2Referenz();

        if (person1Referenz != null && person1Referenz.getId() != null && personendatenInternPerReferenzExtern.containsKey(person1Referenz)) {
          person1 = personendatenInternPerReferenzExtern.get(person1Referenz);
        } else {
          KandidaturReferenz kandidatur1Referenz = kandidaturVerknuepfung.getKandidatur1();

          if (kandidatur1Referenz != null && kandidaturInternPerKandidaturReferenzExtern.containsKey(kandidatur1Referenz)) {
            person1 = kandidaturInternPerKandidaturReferenzExtern.get(kandidatur1Referenz);
          }
        }

        if (person2Referenz != null && person2Referenz.getId() != null && personendatenInternPerReferenzExtern.containsKey(person2Referenz)) {
          person2 = personendatenInternPerReferenzExtern.get(person2Referenz);
        } else {
          KandidaturReferenz kandidatur2Referenz = kandidaturVerknuepfung.getKandidatur2();

          if (kandidatur2Referenz != null && kandidaturInternPerKandidaturReferenzExtern.containsKey(kandidatur2Referenz)) {
            person2 = kandidaturInternPerKandidaturReferenzExtern.get(kandidatur2Referenz);
          }
        }

        if (person1 != null && person2 != null) {
          result.add(personendatenVerknuepfer.verknuepfe(mappe(kandidaturVerknuepfung.getVerknuepfungsArt()), person1, person2, mappe(kandidaturVerknuepfung.getVerknuepfungsGrundlage()),
              mappe(kandidaturVerknuepfung.getVerknuepfungsStatus())));
        }
      }
    }

    return result;
  }

  protected de.ivu.elect.business.person.entity.VerknuepfungsStatus mappe(VerknuepfungsStatus verknuepfungsStatus) {
    return de.ivu.elect.business.person.entity.VerknuepfungsStatus.valueOf(verknuepfungsStatus.name());
  }

  protected de.ivu.elect.business.person.entity.VerknuepfungsGrundlage mappe(VerknuepfungsGrundlage verknuepfungsGrundlage) {
    return de.ivu.elect.business.person.entity.VerknuepfungsGrundlage.valueOf(verknuepfungsGrundlage.name());
  }

  protected de.ivu.elect.business.person.entity.VerknuepfungsArt mappe(VerknuepfungsArt verknuepfungsArt) {
    return de.ivu.elect.business.person.entity.VerknuepfungsArt.valueOf(verknuepfungsArt.name());
  }

  protected boolean isKandidaturInternZuUebernehmen(Kandidatur kandidaturIntern) {
    return true;
  }

  protected Map<PersonReferenz, Kandidatur> mapKandidaturen(Wahl wahlExtern, Map<WahlvorschlagReferenz, Wahlvorschlag> wahlvorschlagInternPerReferenzExtern,
      Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    Map<PersonReferenz, Kandidatur> result = new HashMap<>();

    for (de.ivu.elect.interfaces.core.Direktkandidatur direktkandidaturExtern : wahlExtern.getDirektkandidaturen()) {
      Direktkandidatur direktkandidaturIntern = direktkandidaturFactory.create();
      direktkandidaturIntern.setCustomDataXml(direktkandidaturExtern.getCustomData());
      direktkandidaturIntern.setDirektkandidat((Direktkandidat) wahlvorschlagInternPerReferenzExtern.get(direktkandidaturExtern.getDirektkandidat()));

      mapKandidatur(result, direktkandidaturExtern, direktkandidaturIntern, veranstaltungInternPerReferenzExtern);
    }

    for (de.ivu.elect.interfaces.core.Listenkandidatur listenkandidaturExtern : wahlExtern.getListenkandidaturen()) {
      Listenkandidatur listenkandidaturIntern = listenkandidaturFactory.create();
      listenkandidaturIntern.setCustomDataXml(listenkandidaturExtern.getCustomData());
      listenkandidaturIntern.setListenkandidaturArt(map(listenkandidaturExtern.getListenkandidaturArt()));
      listenkandidaturIntern.setListe((Liste) wahlvorschlagInternPerReferenzExtern.get(listenkandidaturExtern.getListe()));
      listenkandidaturIntern.setRelativePosition(listenkandidaturExtern.getRelativePosition());
      if (listenkandidaturIntern.getRelativePosition() == null) {
        listenkandidaturIntern.setRelativePosition(listenkandidaturExtern.getListenposition()); // Kompatibilität
      }
      listenkandidaturIntern.setVorgegebenePosition(listenkandidaturExtern.getVorgegebenePosition());
      listenkandidaturIntern.setEingereichtePosition(listenkandidaturExtern.getEingereichtePosition());
      if (listenkandidaturIntern.getEingereichtePosition() == null) {
        listenkandidaturIntern.setEingereichtePosition(listenkandidaturExtern.getListenposition()); // Kompatibilität
      }
      if (isNurWas() && listenkandidaturIntern.getVorgegebenePosition() == null) {
        listenkandidaturIntern.setVorgegebenePosition(listenkandidaturExtern.getListenposition()); // ELECTDD-584
      }

      mapListenkandidatur(result, listenkandidaturExtern, listenkandidaturIntern, veranstaltungInternPerReferenzExtern);
    }

    return result;
  }

  private Map<KandidaturReferenz, Kandidatur> mapKandidaturenNachReferenz(Collection<Kandidatur> kandidaturenIntern) {
    Map<KandidaturReferenz, Kandidatur> result = new HashMap<>();

    for (Kandidatur kandidatur : kandidaturenIntern) {
      result.put(wahlInternExternMapperUtil.mappeKandidaturZuReferenz(kandidatur), kandidatur);
    }

    return result;
  }

  private void mapListenkandidatur(Map<PersonReferenz, Kandidatur> result, de.ivu.elect.interfaces.core.Listenkandidatur listenkandidaturExtern, Listenkandidatur listenkandidaturIntern,
      Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    mapKandidatur(result, listenkandidaturExtern, listenkandidaturIntern, veranstaltungInternPerReferenzExtern);

    Long anzahlNennungen = listenkandidaturExtern.getAnzahlNennungen();

    if (anzahlNennungen != null) {
      listenkandidaturIntern.setAnzahlNennungen(anzahlNennungen);
    }
  }

  // Cf. WahlInternExternMapper#mapKandidaturAttribute!!!
  protected void mapKandidatur(Map<PersonReferenz, Kandidatur> result, de.ivu.elect.interfaces.core.Kandidatur source, Kandidatur target,
      Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    Wahlvorschlag wahlvorschlag = target.getWahlvorschlag();

    // ELECTMUC-1567, ELECTMUC-2839
    WahlvorschlagStatus wahlvorschlagStatus = null;

    if (wahlvorschlag != null) {
      wahlvorschlagStatus = wahlvorschlag.getWahlvorschlagStatus();
    }

    mapPersonendaten(source, target, veranstaltungInternPerReferenzExtern);

    target.setBerufPraesentation(source.getBerufPraesentation());

    target.setGeburtsortPraesentation(source.getGeburtsortPraesentation());

    KandidaturQuelle kandidaturQuelle = mappeKandidaturQuelle(source.getKandidaturQuelle());

    if (kandidaturQuelle != null) { // TODO @Nullable zur Abwärtskompatibilität; irgendwann entfernen
      target.setKandidaturQuelle(kandidaturQuelle);
    }

    KandidaturStatus kandidaturStatus = mappeKandidaturStatus(source.getKandidaturStatus());

    if (kandidaturStatus == null) { // TODO Abwärtskompatibilität; irgendwann entfernen (Cf. ELECT-2591)
      kandidaturStatus = mappeZugelassen(source.getZugelassen());
    }

    target.setKandidaturStatus(kandidaturStatus);

    target.setNamePraesentation(source.getNamePraesentation());

    target.setWaehlbar(mappe(source.getWaehlbar()));
    target.setWohnortPraesentation(source.getWohnortPraesentation());

    if (source.getErsatzkandidatur() != null) {
      Ersatzkandidatur ersatzkandidaturIntern = ersatzkandidaturFactory.create();
      ersatzkandidaturIntern.setCustomDataXml(source.getErsatzkandidatur().getCustomData());

      target.setZugeordneteErsatzkandidatur(ersatzkandidaturIntern);

      mapKandidatur(result, source.getErsatzkandidatur(), ersatzkandidaturIntern, veranstaltungInternPerReferenzExtern);
    }

    // ELECTMUC-1567, ELECTMUC-2839
    if (wahlvorschlag != null && wahlvorschlagStatus != null) {
      wahlvorschlag.setWahlvorschlagStatus(wahlvorschlagStatus);
    }

    result.put(wahlInternExternMapperUtil.mappePersonendatenZuReferenz(source), target);
  }

  private Map<WahlvorschlagReferenz, Wahlvorschlag> mapWahlvorschlaege(Wahl wahlExtern, Map<GruppeImGebietReferenz, GruppeImGebiet> gruppeImGebietInternPerReferenzExtern) {
    Map<WahlvorschlagReferenz, Wahlvorschlag> result = new HashMap<>();

    List<Wahlvorschlag> wahlvorschlaegeIntern = new ArrayList<>();

    for (de.ivu.elect.interfaces.core.Direktkandidat direktkandidatExtern : wahlExtern.getDirektkandidaten()) {
      Direktkandidat direktkandidatIntern = new Direktkandidat();

      mapWahlvorschlag(result, wahlvorschlaegeIntern, direktkandidatExtern, direktkandidatIntern, gruppeImGebietInternPerReferenzExtern);
    }

    Map<String, Listenverbindung> listenverbindungNachId = new HashMap<>();

    for (de.ivu.elect.interfaces.core.Liste listeExtern : wahlExtern.getListen()) {
      Liste listeIntern = new Liste();
      mapListe(result, wahlvorschlaegeIntern, listeExtern, listeIntern, gruppeImGebietInternPerReferenzExtern, listenverbindungNachId);
    }

    for (de.ivu.elect.interfaces.core.ReferendumOption referendumOptionExtern : wahlExtern.getReferendumOptionen()) {
      ReferendumOption referendumOptionIntern = new ReferendumOption();
      referendumOptionIntern.setLabel(referendumOptionExtern.getLabel());
      referendumOptionIntern.setKurzbezeichnung(referendumOptionExtern.getKurzbezeichnung());

      Long position = referendumOptionExtern.getPosition();

      // Abwärtskompatibilität... ELECT-2413 TODO irgendwan(tm) entfernen
      if (position == null) {
        position = referendumOptionExtern.getWahlvorschlagReferenz().getPosition();
      }
      referendumOptionIntern.setPosition(position);

      mapWahlvorschlag(result, wahlvorschlaegeIntern, referendumOptionExtern, referendumOptionIntern, gruppeImGebietInternPerReferenzExtern);
    }

    return result;
  }

  private void mapListe(Map<WahlvorschlagReferenz, Wahlvorschlag> result, List<Wahlvorschlag> wahlvorschlaege, de.ivu.elect.interfaces.core.Liste listeExtern, Liste listeIntern,
      Map<GruppeImGebietReferenz, GruppeImGebiet> gruppenImGebietIntern, Map<String, Listenverbindung> listenVerbindungNachId) {
    mapWahlvorschlag(result, wahlvorschlaege, listeExtern, listeIntern, gruppenImGebietIntern);
    listeIntern.setListenverbindung(findListenverbindungByBezeichnungOrDefault(listenVerbindungNachId, listeExtern));
  }

  @Nullable
  private Listenverbindung findListenverbindungByBezeichnungOrDefault(Map<String, Listenverbindung> listenVerbindungNachId, de.ivu.elect.interfaces.core.Liste listeExtern) {
    String listenverbindungBezeichnung = listeExtern.getListenverbindung();

    if (isNotBlank(listenverbindungBezeichnung)) {
      String id = listeExtern.getListenverbindungId();
      if (id == null) {
        id = listenverbindungBezeichnung;
      }

      Listenverbindung listenverbindung = listenVerbindungNachId.get(id);
      if (listenverbindung == null) {
        listenverbindung = new Listenverbindung();
        listenverbindung.setBezeichnung(listenverbindungBezeichnung);
        listenVerbindungNachId.put(id, listenverbindung);
      }

      return listenverbindung;
    }

    return null;
  }

  private void mapWahlvorschlag(Map<WahlvorschlagReferenz, Wahlvorschlag> result, List<Wahlvorschlag> alleWahlvorschlaege, de.ivu.elect.interfaces.core.Wahlvorschlag wahlvorschlagExtern,
      Wahlvorschlag wahlvorschlagIntern, Map<GruppeImGebietReferenz, GruppeImGebiet> gruppenImGebietIntern) {
    WahlvorschlagReferenz wahlvorschlagReferenz = wahlvorschlagExtern.getWahlvorschlagReferenz();

    wahlvorschlagIntern.setGruppeImGebiet(gruppenImGebietIntern.get(wahlvorschlagReferenz.getGruppeImGebietReferenz()));
    // wahlvorschlagIntern.setPosition(wahlvorschlagReferenz.getPosition());

    WahlvorschlagStatus wahlvorschlagStatus = mappeWahlvorschlagStatus(wahlvorschlagExtern.getWahlvorschlagStatus());

    if (wahlvorschlagStatus == null) {
      // TODO: Abwärtskompatibilität; irgendwann entfernen
      wahlvorschlagStatus = wahlvorschlagExtern.isZugelassen() ? WahlvorschlagStatus.ZUGELASSEN : WahlvorschlagStatus.NICHT_ZUGELASSEN;
    }

    wahlvorschlagIntern.setWahlvorschlagStatus(wahlvorschlagStatus);

    if (wahlvorschlagExtern.getZeitpunktDerEinreichung() != null) {
      wahlvorschlagIntern.setZeitpunktDerEinreichung(wahlvorschlagExtern.getZeitpunktDerEinreichung());
    }

    if (wahlvorschlagExtern.getUnterstuetzerErfassbarAb() != null) {
      wahlvorschlagIntern.setUnterstuetzerErfassbarAb(wahlvorschlagExtern.getUnterstuetzerErfassbarAb());
    }

    if (wahlvorschlagExtern.getAnzahlUnterstuetzerExternGueltig() != null) {
      wahlvorschlagIntern.setAnzahlUnterstuetzerGeeignetErfasstExtern(wahlvorschlagExtern.getAnzahlUnterstuetzerExternGueltig());
    }

    if (wahlvorschlagExtern.getAnzahlUnterstuetzerExternUngueltig() != null) {
      wahlvorschlagIntern.setAnzahlUnterstuetzerNichtGeeignetErfasstExtern(wahlvorschlagExtern.getAnzahlUnterstuetzerExternUngueltig());
    }

    // ELECT-8587, Kennwort/Kurzname UNVERÄNDERT übernehmen!
    wahlvorschlagIntern.setKennwort(wahlvorschlagExtern.getKennwort());
    wahlvorschlagIntern.setKurzname(wahlvorschlagExtern.getKurzname());
    wahlvorschlagIntern.setZusatzbezeichnung(wahlvorschlagExtern.getZusatzbezeichnung());

    result.put(wahlvorschlagReferenz, wahlvorschlagIntern);

    alleWahlvorschlaege.add(wahlvorschlagIntern);
  }

  private Map<GruppeImGebietReferenz, GruppeImGebiet> mapGruppenImGebiet(Wahl wahlExtern, Map<GebietReferenz, Gebiet> gebieteIntern, Map<GruppeReferenz, Gruppe> gruppenIntern) {
    Map<GruppeImGebietReferenz, GruppeImGebiet> result = new HashMap<>();
    for (de.ivu.elect.interfaces.core.GruppeImGebiet gruppeImGebietExtern : wahlExtern.getGruppenImGebiet()) {
      GruppeImGebiet gruppeImGebietIntern = gruppeImGebietFactory.create();
      gruppeImGebietIntern.setCustomDataXml(gruppeImGebietExtern.getCustomData());
      GruppeImGebietReferenz gruppeImGebietReferenz = gruppeImGebietExtern.getGruppeImGebietReferenz();
      gruppeImGebietIntern.setGebiet(gebieteIntern.get(gruppeImGebietReferenz.getGebiet()));

      gruppeImGebietIntern.setGruppe(gruppenIntern.get(gruppeImGebietReferenz.getGruppe()));

      gruppeImGebietIntern.setName(gruppeImGebietExtern.getName());
      gruppeImGebietIntern.setKurzname(gruppeImGebietExtern.getKurzname());
      gruppeImGebietIntern.setZusatzbezeichnung(gruppeImGebietExtern.getZusatzbezeichnung());
      gruppeImGebietIntern.setRelativePosition(gruppeImGebietExtern.getRelativePosition());
      if (gruppeImGebietIntern.getRelativePosition() == null) {
        gruppeImGebietIntern.setRelativePosition(gruppeImGebietExtern.getPosition()); // kompatibilität
      }
      gruppeImGebietIntern.setVorgegebenePosition(gruppeImGebietExtern.getVorgegebenePosition());
      gruppeImGebietIntern.setEingereichtePosition(gruppeImGebietExtern.getEingereichtePosition());

      postMappeGruppenImGebiet(gruppeImGebietIntern, gruppeImGebietExtern);

      result.put(gruppeImGebietReferenz, gruppeImGebietIntern);
    }
    return result;
  }

  protected void postMappeGruppenImGebiet(GruppeImGebiet gruppeImGebietIntern, de.ivu.elect.interfaces.core.GruppeImGebiet gruppeImGebietExtern) {
    // nichts zu tun...
  }

  private Map<GruppeReferenz, Gruppe> mapGruppen(Wahl wahlExtern, Wahlobject wahlIntern) {
    Map<GruppeReferenz, Gruppe> result = new HashMap<>();

    long letzteRelativePosition = 0;

    for (de.ivu.elect.interfaces.core.PolitischeGruppe politischeGruppeExtern : wahlExtern.getPolitischeGruppen()) {
      PolitischeGruppe politischeGruppeIntern = politischeGruppeFactory.create();
      politischeGruppeIntern.setCustomDataXml(politischeGruppeExtern.getCustomData());
      politischeGruppeIntern.setMinderheit(Boolean.TRUE.equals(politischeGruppeExtern.isMinderheit()));
      politischeGruppeIntern.setPrivilegiert(Boolean.TRUE.equals(politischeGruppeExtern.isPrivilegiert()));

      mapGruppe(result, politischeGruppeExtern, politischeGruppeIntern, letzteRelativePosition, wahlIntern);

      letzteRelativePosition = politischeGruppeIntern.getRelativePosition();
    }

    for (de.ivu.elect.interfaces.core.Gruppe gruppeExtern : wahlExtern.getGruppen()) {
      Gruppe gruppeIntern = gruppeFactory.create();
      gruppeIntern.setCustomDataXml(gruppeExtern.getCustomData());

      mapGruppe(result, gruppeExtern, gruppeIntern, letzteRelativePosition, wahlIntern);

      letzteRelativePosition = gruppeIntern.getRelativePosition();
    }

    return result;
  }

  private void mapGruppe(Map<GruppeReferenz, Gruppe> result, de.ivu.elect.interfaces.core.Gruppe gruppeExtern, Gruppe gruppeIntern, long letzteRelativePosition, Wahlobject wahlIntern) {
    GruppeReferenz gruppeReferenz = gruppeExtern.getGruppeReferenz();
    gruppeIntern.setWahl(wahlIntern);
    gruppeIntern.setSchluessel(gruppeReferenz.getSchluessel());

    gruppeIntern.setName(gruppeExtern.getName());
    gruppeIntern.setKurzname(gruppeExtern.getKurzname());
    gruppeIntern.setZusatzbezeichnung(gruppeExtern.getZusatzbezeichnung());
    gruppeIntern.setGruppeArt(mappe(gruppeExtern.getGruppeArt()));
    gruppeIntern.setLogo(mappe(gruppeExtern.getLogo()));
    gruppeIntern.setFarbe(gruppeExtern.getFarbe());
    gruppeIntern.setFarbeExtern(gruppeExtern.getFarbeExtern());
    gruppeIntern.setInPraesentation(gruppeExtern.isInPraesentation());

    gruppeIntern.setRelativePosition(gruppeExtern.getRelativePosition());

    if (gruppeIntern.getRelativePosition() == null) {
      gruppeIntern.setRelativePosition(letzteRelativePosition + 1);
    }

    gruppeIntern.setVorgegebenePosition(gruppeExtern.getVorgegebenePosition());

    result.put(gruppeReferenz, gruppeIntern);
  }

  protected Bild mappe(de.ivu.elect.interfaces.core.Bild bild) {
    return bildMapper.intern(bild);
  }

  protected Map<GebietReferenz, Gebiet> mapGebiete(Wahl wahlExtern) {
    return gebietMapper.mapGebiete(wahlExtern);
  }

  // TODO Abwärtskompatibilität; irgendwann entfernen (Cf. ELECT-2591)
  public KandidaturStatus mappeZugelassen(de.ivu.elect.interfaces.core.Zulassung zugelassen) {
    switch (zugelassen) {
      case NICHT_ZUGELASSEN :
        return KandidaturStatus.NICHT_ZUGELASSEN;
      case ZUGELASSEN :
        return KandidaturStatus.ZUGELASSEN;
      case UNBEKANNT :
        return KandidaturStatus.OFFEN;
    }

    throw new IllegalArgumentException("Die Zulassung [name=" + zugelassen + "] kann nicht in einen KandidaturStatus übersetzt werden!");
  }

  @Nullable
  public KandidaturStatus mappeKandidaturStatus(de.ivu.elect.interfaces.core.KandidaturStatus kandidaturStatus) {
    if (kandidaturStatus == null) {
      // TODO: Abwärtskompatibilität; irgendwann entfernen
      return null;
    } else if (de.ivu.elect.interfaces.core.KandidaturStatus.UNGEPRUEFT.equals(kandidaturStatus)) {
      // ELECTDD-119
      // TODO: Abwärtskompatibilität; irgendwann entfernen
      return KandidaturStatus.OFFEN;
    }

    return KandidaturStatus.valueOf(kandidaturStatus.name());
  }

  @Nullable
  public KandidaturQuelle mappeKandidaturQuelle(de.ivu.elect.interfaces.core.KandidaturQuelle kandidaturQuelle) {
    if (kandidaturQuelle == null) {
      // TODO: Abwärtskompatibilität; irgendwann entfernen
      return null;
    }

    return KandidaturQuelle.valueOf(kandidaturQuelle.name());
  }

  @Nullable
  public WahlvorschlagStatus mappeWahlvorschlagStatus(de.ivu.elect.interfaces.core.WahlvorschlagStatus wahlvorschlagStatus) {
    if (wahlvorschlagStatus == null) {
      // TODO: Abwärtskompatibilität; irgendwann entfernen
      return null;
    } else if (de.ivu.elect.interfaces.core.WahlvorschlagStatus.UNGEPRUEFT.equals(wahlvorschlagStatus)) {
      // ELECTDD-119
      // TODO: Abwärtskompatibilität; irgendwann entfernen
      return WahlvorschlagStatus.OFFEN;
    }

    return WahlvorschlagStatus.valueOf(wahlvorschlagStatus.name());
  }

  protected void mapPersonendaten(Person personExtern, Personendaten personIntern, Map<VeranstaltungReferenz, Veranstaltung> veranstaltungInternPerReferenzExtern) {
    personMapper.intern(personExtern, personIntern);
    teilnahmeMapper.mappeTeilnahme(personExtern, personIntern, veranstaltungInternPerReferenzExtern);
  }

  protected ListenkandidaturArt map(de.ivu.elect.interfaces.core.ListenkandidaturArt listenkandidaturArt) {
    // NOTE, dass aufgrund der Abwärtskompatibilität die ListenkandidaturArt optional definiert ist.
    if (listenkandidaturArt == null) {
      return ListenkandidaturArt.LISTENKANDIDATUR;
    }

    return ListenkandidaturArt.valueOf(listenkandidaturArt.name());
  }

  protected Ergebnisart mappe(de.ivu.elect.interfaces.core.Ergebnisart ergebnisart) {
    return Ergebnisart.valueOf(ergebnisart.name());
  }

  protected Wahlausschussrolle mappe(de.ivu.elect.interfaces.core.Wahlausschussrolle wahlausschussrolle) {
    return Wahlausschussrolle.valueOf(wahlausschussrolle.name());
  }

  protected Waehlbarkeit mappe(de.ivu.elect.interfaces.core.Waehlbarkeit waehlbar) {
    return Waehlbarkeit.valueOf(waehlbar.name());
  }

  protected GruppeImGebietStatus mappe(de.ivu.elect.interfaces.core.GruppeImGebietStatus status) {
    return GruppeImGebietStatus.valueOf(status.name());
  }

  public static Stimmenart mappe(de.ivu.elect.interfaces.core.Stimmenart stimmenart) {
    if (de.ivu.elect.interfaces.core.Stimmenart.KEINE.equals(stimmenart)) {
      return Stimmenart.GESAMT; // ELECT-2007 Unterstützung für alte Dateien
    }

    return Stimmenart.valueOf(stimmenart.name());
  }

  protected GruppeArt mappe(de.ivu.elect.interfaces.core.GruppeArt gruppeArt) {
    return GruppeArt.valueOf(gruppeArt.name());
  }

  public List<DokumentVorlage> mappeDokumentVorlagen(List<de.ivu.elect.interfaces.core.DokumentVorlage> sources) {
    return new ArrayList<>(dokumentVorlageMapper.intern(sources));
  }

  public List<WahlParameter> mappeWahlParameter(List<de.ivu.elect.interfaces.core.WahlParameter> sources) {
    return new ArrayList<>(wahlParameterMapper.intern(sources));
  }

  protected boolean isWasFeaturesEnabled() {
    return isNurWas() || isWusWasZusammen();
  }

  protected boolean isNurWas() {
    return wusFeaturesAktiviert.isNurWas();
  }

  protected boolean isWusFeaturesEnabled() {
    return isNurWus() || isWusWasZusammen();
  }

  protected boolean isNurWus() {
    return wusFeaturesAktiviert.isNurWus();
  }

  protected boolean isWusWasZusammen() {
    return wusFeaturesAktiviert.isWusWasZusammen();
  }
}
