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

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

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

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

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.datei.entity.DateiExport;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisDAO;
import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.control.ErgebnisDatenCreator;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Praesentationsexportart;
import de.ivu.elect.business.ergebnis.entity.Praesentationsexportausloeser;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.internet.boundary.PraesentationsexportDAO;
import de.ivu.elect.business.internet.entity.InternetSeite;
import de.ivu.elect.business.internet.entity.PraesentationErgebnisArt;
import de.ivu.elect.business.internet.entity.Praesentationsexport;
import de.ivu.elect.business.praesentation.entity.PraesentationErfassungsgebieteZurueckhalten;
import de.ivu.elect.business.stimmeingabe.boundary.ErgebniseingangDAO;
import de.ivu.elect.business.stimmeingabe.control.ErgebniseingangEingangssequenznummerGenerator;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.system.boundary.SystemLogWriter;
import de.ivu.elect.business.system.entity.SystemLogQuelle;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlParameterLoader;
import de.ivu.elect.jee.faces.Messages;


import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.PREASENTATIION_ERFASSUNGSGEBIETE_PRO_WAHLGEBIET_NOTWENDIG;
import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.PREASENTATIION_ERFASSUNGSGEBIETE_ZURUECKHALTEN;

public class PraesentationExportObjectErzeuger implements Serializable {

  private static final long serialVersionUID = 1L;

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

  public static final long INITIALE_NUMMER = ErgebniseingangEingangssequenznummerGenerator.ERSTE_ZU_VERGEBENE_NUMMER - 1;

  public static final long NUMMER_FUER_ATOMATISCHEN_EXPORT = INITIALE_NUMMER - 1L;

  @Inject
  private transient ErgebnisDAO ergebnisDAO;

  @Inject
  private transient ErgebniseingangDAO ergebniseingangDAO;

  @Inject
  private transient WahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient PraesentationExportExchange exportExchange;

  @Inject
  private transient ErgebnisDatenCreator ergebnisDatenCreator;

  @Inject
  private transient PraesentationsexportDAO praesentationsexportDAO;

  @Inject
  private transient PraesentationErgebnisArtBestimmer praesentationErgebnisArtBestimmer;

  @Inject
  private transient WahlParameterLoader wahlParameterLoader;

  @Inject
  private transient SystemLogWriter systemLogWriter;

  @Inject
  private transient Messages messages;

  @Inject
  private transient PraesentationExportInternetSeitenExtractor praesentationExportInternetSeitenExtractor;

  public PraesentationExportObjectErzeuger() {
    super();
  }

  public PraesentationExportObject getExportObject(PraesentationExportContext praesentationExportContext, FileFormat fileFormat,
                                                   DateiExport dateiExport) {
    LOG.info("Lade Export-Objekt - ergebnis");
    Ergebnis ergebnis = ergebnisDAO.attach(praesentationExportContext.getErgebnis());

    LOG.info("Lade Export-Objekt - ergebniseingaenge");
    List<Ergebniseingang> ergebniseingaenge = ergebniseingangDAO.findByEingeflossenInErgebnis(ergebnis);

    LOG.info("Lade Export-Objekt - alleGebiete");
    List<Wahldurchfuehrungsgebiet> alleGebiete = wahldurchfuehrungsgebietDAO.findByWahl(ergebnis.getWahl());

    LOG.info("Lade Export-Objekt - auszuschliessendeErfassungsgebiete");
    Set<Wahldurchfuehrungsgebiet> auszuschliessendeErfassungsgebiete = bestimmeAuszuschliessendeErfassungsgebiete(ergebnis, alleGebiete, ergebniseingaenge);

    LOG.info("Lade Export-Objekt - nichtMehrAusgeschlosseneErfassungsgebiete");
    Set<Wahldurchfuehrungsgebiet> nichtMehrAusgeschlosseneErfassungsgebiete = bestimmeNichtMehrAusgeschlosseneErfassungsgebiete(ergebnis,
            alleGebiete, ergebniseingaenge);

    LOG.info("Lade Export-Objekt - ergebnisDaten");
    ErgebnisDaten ergebnisDaten = ergebnisDatenCreator.createErgebnisDatenPraesentation(ergebnis, auszuschliessendeErfassungsgebiete);
    LOG.info("Lade Export-Objekt - laden done");


    Praesentationsexport praesentationsexport = findOrCreatePraesentationsexport(praesentationExportContext, fileFormat, ergebnis, dateiExport.getDatei());

    List<Wahldurchfuehrungsgebiet> seitLetzemExportGeaenderteErfassungsgebiete = bestimmeSeitLetzemExportGeaenderteErfassungsgebiete(
            praesentationsexport, ergebniseingaenge, nichtMehrAusgeschlosseneErfassungsgebiete);

    if (ergebnis.getEingangssequenznummer() != null) {
      praesentationsexport.setLetzteEingangssequenznummer(ergebnis.getEingangssequenznummer());
    } else {
      praesentationsexport.setLetzteEingangssequenznummer(INITIALE_NUMMER);
    }

    if (exportExchange.isDateinameWirdAngepasst(praesentationExportContext, fileFormat)) {
      dateiExport.getDatei()
              .setOriginalDateiname(exportExchange.getExportDateiname(praesentationExportContext, fileFormat, praesentationsexport));
    }

    // ELECT-2229
    ergebniseingaenge = filterErgebniseingaenge(ergebniseingaenge, auszuschliessendeErfassungsgebiete);

    seitLetzemExportGeaenderteErfassungsgebiete = filterErfassungsgebiete(seitLetzemExportGeaenderteErfassungsgebiete, auszuschliessendeErfassungsgebiete);

    // ELECTMUC-138
    Set<Wahldurchfuehrungsgebiet> gebieteDieNichtImExportAngezeigtWerdenSollen = bestimmeGebietDieNichtExportiertWerdenSollen(ergebnis, alleGebiete);

    // ELECTMUC-308
    PraesentationErgebnisArt ergebnisartPraesentation = bestimmeErgebnisartPraesentation(ergebnis, alleGebiete);


    if (!auszuschliessendeErfassungsgebiete.isEmpty()) {
      // ELECT-8436
      systemLogWriter.writeInfoLogMessageFuerMandant(ergebnis, messages.getMessageForMessageKey("presentation.generieren.gebiete.zurueckhalten", auszuschliessendeErfassungsgebiete.size()), SystemLogQuelle.PRAESENTATION_GENERIEREN);
    }


    PraesentationExportWahldaten praesentationExportWahldaten = new PraesentationExportWahldaten(ergebnisDaten, ergebniseingaenge,
            seitLetzemExportGeaenderteErfassungsgebiete, gebieteDieNichtImExportAngezeigtWerdenSollen, ergebnisartPraesentation);

    if (praesentationExportWahldaten.getInternetSeiten().isEmpty()) {
      LOG.info("Keine manuellen Internet-Seiten gefunden");

      if (praesentationExportInternetSeitenExtractor.isDokumentvorlageVerwenden(ergebnis.getWahl()))  {
        LOG.info("Verwende InternetSeiten aus Dokumentvorlage aktiviert");
        List<InternetSeite> internetSeiten = praesentationExportInternetSeitenExtractor.extrahiereInternetSeiten(ergebnis.getWahl());
        if (!internetSeiten.isEmpty()) {
          LOG.info("Verwende InternetSeiten aus Dokumentvorlage: " + internetSeiten.size());
          praesentationExportWahldaten.setInternetSeiten(internetSeiten);
        }
      } else {
        LOG.info("Verwende InternetSeiten aus Dokumentvorlage deaktiviert");

      }

    } else {
      LOG.info("Manuelle Internet-Seiten gefunden: " + praesentationExportWahldaten.getInternetSeiten().size());
    }

    return new PraesentationExportObject(praesentationExportWahldaten);
  }


  /**
   * ELECTMUC-308: Das Ergebnis ist nur ein AMTLICHES ENDERGEBNIS, wenn das Ergebnis ENDGÜLTIG und das oberste Gebiet
   * FREIGEGEBEN ist
   * <p>
   * ELECTDD-354
   */
  private PraesentationErgebnisArt bestimmeErgebnisartPraesentation(Ergebnis ergebnis, List<Wahldurchfuehrungsgebiet> alleGebiete) {
    return praesentationErgebnisArtBestimmer.bestimmeErgebnisartPraesentation(ergebnis, getWurzelgebiet(alleGebiete));
  }

  protected Wahldurchfuehrungsgebiet getWurzelgebiet(List<Wahldurchfuehrungsgebiet> alleGebiete) {
    if (alleGebiete.isEmpty()) {
      throw new IllegalStateException("Keine Gebiete");
    }
    return alleGebiete.get(0).getWurzelgebiet();
  }

  /**
   * exportiert werden sollen NICHT die ERFASSUNGSGEBIETE, wenn das Ergebnis VORLÄUFIG ist, oder beim ENDGÜLTIGEN
   * Ergebnis das oberste Gebiet NICHT FREIGEGEBEN ist
   */
  @Deprecated
  protected Set<Wahldurchfuehrungsgebiet> bestimmeGebietDieNichtExportiertWerdenSollen(Ergebnis ergebnis,
                                                                                       List<Wahldurchfuehrungsgebiet> alleGebiete) {
    return Collections.emptySet();
  }

  private List<Wahldurchfuehrungsgebiet> filterErfassungsgebiete(List<Wahldurchfuehrungsgebiet> seitLetzemExportGeaenderteErfassungsgebiete,
                                                                 Set<Wahldurchfuehrungsgebiet> auszuschliessendeErfassungsgebiete) {
    List<Wahldurchfuehrungsgebiet> result = new ArrayList<>(seitLetzemExportGeaenderteErfassungsgebiete.size());
    for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : seitLetzemExportGeaenderteErfassungsgebiete) {
      if (!auszuschliessendeErfassungsgebiete.contains(wahldurchfuehrungsgebiet)) {
        result.add(wahldurchfuehrungsgebiet);
      }
    }
    return result;
  }

  private List<Ergebniseingang> filterErgebniseingaenge(List<Ergebniseingang> ergebniseingaenge,
                                                        Set<Wahldurchfuehrungsgebiet> auszuschliessendeErfassungsgebiete) {
    return ergebniseingaenge.stream()
            .filter(ergebniseingang -> !auszuschliessendeErfassungsgebiete.contains(ergebniseingang.getWahldurchfuehrungsgebiet()))
            .collect(Collectors.toCollection(() -> new ArrayList<>(ergebniseingaenge.size())));
  }

  // ELECT-2229 jeweils das zu letzt erfasste Erfassungsgebiet einen Stimmkreises/Direktwahlgebietes soll ausgeschlossen werden, es sein denn dieses Gebiet ist abgeschlossen
  protected Set<Wahldurchfuehrungsgebiet> bestimmeAuszuschliessendeErfassungsgebiete(Ergebnis ergebnis,
                                                                                     List<Wahldurchfuehrungsgebiet> alleGebiete, List<Ergebniseingang> ergebniseingaenge) {

    if (isErfassungsgebieteZurueckhaltenBeiWahlNotwendig(ergebnis.getWahl())) {
      return bestimmeAuszuschliessendeOderAusgeschlosseneErfassungsgebiete(ergebnis, alleGebiete, ergebniseingaenge, false);
    }

    return new HashSet<>();
  }

  protected boolean isErfassungsgebieteZurueckhaltenBeiWahlNotwendig(Wahl wahl) {
    return getErfassungsgebieteZurueckhalten(wahl).isErfassungsgebieteZurueckhaltenNotwendig() || getPraesentationErfassungsgebieteNotwendig(wahl) > 0;
  }

  private PraesentationErfassungsgebieteZurueckhalten getErfassungsgebieteZurueckhalten(Wahl wahl) {
    return wahlParameterLoader.resolveEnumValue(wahl, PREASENTATIION_ERFASSUNGSGEBIETE_ZURUECKHALTEN, PraesentationErfassungsgebieteZurueckhalten.class);
  }

  private long getPraesentationErfassungsgebieteNotwendig(Wahl wahl) {
    Long aLong = wahlParameterLoader.resolveLongValue(wahl, PREASENTATIION_ERFASSUNGSGEBIETE_PRO_WAHLGEBIET_NOTWENDIG);
    if (aLong == null) {
      return 0L;
    }
    return aLong;
  }

  /**
   * Diese Methode wird verwendet, um wahlweise entweder die momentan auszuschließenden oder die früher ausgeschlossenen
   * und nun nicht mehr auszuschließenden Erfassungsgebiete zu ermitteln.
   *
   * @param ergebnis
   * @param alleGebiete
   * @param ergebniseingaenge
   * @param nichtMehrAusgeschlossen true = bestimmt ehemals ausgeschlossene Erfassungsgebiete, false = bestimmt zurzeit auszuschließende
   *                                Erfassungsgebiete
   * @return
   */
  private Set<Wahldurchfuehrungsgebiet> bestimmeAuszuschliessendeOderAusgeschlosseneErfassungsgebiete(Ergebnis ergebnis,
                                                                                                      List<Wahldurchfuehrungsgebiet> alleGebiete, List<Ergebniseingang> ergebniseingaenge, boolean nichtMehrAusgeschlossen) {
    Set<Wahldurchfuehrungsgebiet> result = new HashSet<>();

    final Map<Wahldurchfuehrungsgebiet, Ergebniseingang> ergebniseingaengeProGebiet = mappeErgebniseingaengeAufGebiet(ergebniseingaenge);
    Multimap<Wahldurchfuehrungsgebiet, Wahldurchfuehrungsgebiet> erfassungsgebieteNachObergebiet = bestimmeErfassungsgebieteNachNaechstHoeheremWahlgebiet(alleGebiete);

    for (Wahldurchfuehrungsgebiet obergebiet : erfassungsgebieteNachObergebiet.keySet()) {
      Collection<Wahldurchfuehrungsgebiet> erfassungsgebieteInObergebiet = erfassungsgebieteNachObergebiet.get(obergebiet);
      if (alleGebieteHabenEinenEingang(erfassungsgebieteInObergebiet, ergebniseingaengeProGebiet)) {
        if (isErfassungsgebietInObergebietZurueckhalten(ergebnis, obergebiet) ^ nichtMehrAusgeschlossen) {
          result.add(bestimmeZuletztEingegebenesGebiet(erfassungsgebieteInObergebiet, ergebniseingaengeProGebiet));
        }
      }
    }

    if (!nichtMehrAusgeschlossen) {
      long erfassungsgebieteNotwendig = getPraesentationErfassungsgebieteNotwendig(ergebnis.getWahl());
      if (erfassungsgebieteNotwendig > 0) {
        Wahldurchfuehrungsgebiet oberstesGebiet = alleGebiete.stream().filter(g -> !g.hasUebergeordnetesGebiet()).findFirst().orElse(null);
        Map<Gebiet, Set<Wahldurchfuehrungsgebiet>> alleErfassungsgebieteNachWahlgebiet = new HashMap<>();

        for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : alleGebiete) {
          if (wahldurchfuehrungsgebiet.isErfassungsgebiet()) {
            Gebiet wahlgebiet = wahldurchfuehrungsgebiet.getUebergeordnetesWahlgebiet();

            // ELECTKOM-456
            if (wahlgebiet == null) {
              wahlgebiet = oberstesGebiet;
            }

            if (wahlgebiet != null) {
              alleErfassungsgebieteNachWahlgebiet.computeIfAbsent(wahlgebiet, x -> new HashSet<>()).add(wahldurchfuehrungsgebiet);
            }
          }
        }

        Set<Wahldurchfuehrungsgebiet> erfassteGebiete = ergebniseingaenge.stream().map(Ergebniseingang::getWahldurchfuehrungsgebiet).collect(Collectors.toSet());

        for (Map.Entry<Gebiet, Set<Wahldurchfuehrungsgebiet>> entry : alleErfassungsgebieteNachWahlgebiet.entrySet()) {
          if (!isAusreichendErfasst(entry.getValue(), erfassteGebiete, erfassungsgebieteNotwendig)) {
            result.addAll(entry.getValue());
          }
        }
      }
    }

    return result;
  }

  private boolean isAusreichendErfasst(Set<Wahldurchfuehrungsgebiet> gebieteInsgesamt, Set<Wahldurchfuehrungsgebiet> erfassteGebiete, long erfassungsgebieteNotwendig) {
    long anzahlGesamt = gebieteInsgesamt.size();
    long erfasst = 0;
    for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : gebieteInsgesamt) {
      if (erfassteGebiete.contains(wahldurchfuehrungsgebiet)) {
        erfasst++;
      }
    }

    return ((erfasst * 1d) / (anzahlGesamt * 1d)) * 100d >= erfassungsgebieteNotwendig;
  }

  private boolean isErfassungsgebietInObergebietZurueckhalten(Ergebnis ergebnis, Wahldurchfuehrungsgebiet obergebiet) {
    if (!getErfassungsgebieteZurueckhalten(ergebnis.getWahl()).isWahlgebietMussFreigegebenSein()) {
      return false;
    }

    return !isFreigegeben(ergebnis, obergebiet);
  }

  private boolean isFreigegeben(Ergebnis ergebnis, Gebiet gebiet) {
    if (gebiet == null) {
      return false;
    }
    if (gebiet.castTo(Wahldurchfuehrungsgebiet.class).getEntity().getErgebniseingabestatus(ergebnis).isFreigegeben()) {
      return true;
    }
    return isFreigegeben(ergebnis, gebiet.getUebergeordnetesGebiet());
  }

  @Nullable
  private Wahldurchfuehrungsgebiet bestimmeZuletztEingegebenesGebiet(Collection<Wahldurchfuehrungsgebiet> gebiete,
                                                                     Map<Wahldurchfuehrungsgebiet, Ergebniseingang> ergebniseingaengeProGebiet) {
    long maxSequenznummer = Long.MIN_VALUE;
    Wahldurchfuehrungsgebiet gebietMitMaxSequenznummer = null;

    for (Wahldurchfuehrungsgebiet gebiet : gebiete) {
      Ergebniseingang ergebniseingang = ergebniseingaengeProGebiet.get(gebiet);
      if (ergebniseingang.getEingangssequenznummer() > maxSequenznummer) {
        maxSequenznummer = ergebniseingang.getEingangssequenznummer();
        gebietMitMaxSequenznummer = gebiet;
      }
    }

    return gebietMitMaxSequenznummer;
  }

  // HINT: zur Auswahl des Obergebietes siehe cf. ELECTMUC-962
  private Multimap<Wahldurchfuehrungsgebiet, Wahldurchfuehrungsgebiet> bestimmeErfassungsgebieteNachNaechstHoeheremWahlgebiet(
          List<Wahldurchfuehrungsgebiet> alleGebiete) {
    Multimap<Wahldurchfuehrungsgebiet, Wahldurchfuehrungsgebiet> result = HashMultimap.create();

    for (Wahldurchfuehrungsgebiet erfassungsgebiet : Gebiet.filterErfassungsgebiete(alleGebiete)) {
      result.put(erfassungsgebiet.getErstesUebergeordnetesDirektwahlOderListenwahlOderWahlgebiet(), erfassungsgebiet);
    }

    return result;
  }

  // ELECTMUC-309 bestimme zuvor ausgeschlossene Erfassungsgebiete, die jetzt nicht mehr ausgeschlossen werden
  protected Set<Wahldurchfuehrungsgebiet> bestimmeNichtMehrAusgeschlosseneErfassungsgebiete(Ergebnis ergebnis,
                                                                                            List<Wahldurchfuehrungsgebiet> alleGebiete, List<Ergebniseingang> ergebniseingaenge) {
    if (isErfassungsgebieteZurueckhaltenBeiWahlNotwendig(ergebnis.getWahl())) {
      return bestimmeAuszuschliessendeOderAusgeschlosseneErfassungsgebiete(ergebnis, alleGebiete, ergebniseingaenge, true);
    } else {
      return new HashSet<>();
    }
  }

  private boolean alleGebieteHabenEinenEingang(Collection<Wahldurchfuehrungsgebiet> gebiete,
                                               Map<Wahldurchfuehrungsgebiet, Ergebniseingang> ergebniseingaengeProGebiet) {
    return gebiete.stream().noneMatch(wahldurchfuehrungsgebiet -> ergebniseingaengeProGebiet.get(wahldurchfuehrungsgebiet) == null);
  }

  private Map<Wahldurchfuehrungsgebiet, Ergebniseingang> mappeErgebniseingaengeAufGebiet(List<Ergebniseingang> ergebniseingaenge) {
    Map<Wahldurchfuehrungsgebiet, Ergebniseingang> result = new HashMap<>();
    for (Ergebniseingang ergebniseingang : ergebniseingaenge) {
      result.put(ergebniseingang.getWahldurchfuehrungsgebiet(), ergebniseingang);
    }
    return result;
  }

  private List<Wahldurchfuehrungsgebiet> bestimmeSeitLetzemExportGeaenderteErfassungsgebiete(Praesentationsexport praesentationsexport,
                                                                                             List<Ergebniseingang> ergebniseingaenge, Set<Wahldurchfuehrungsgebiet> nichtMehrAusgeschlosseneErfassungsgebiete) {

    Set<Wahldurchfuehrungsgebiet> result;
    if (nichtMehrAusgeschlosseneErfassungsgebiete == null) {
      result = new HashSet<>();
    } else {
      // Früher ausgeschlossene Erfassungsgebiete sollen diesmal exportiert werden.
      // Beachte: es ist nicht momentan nicht möglich zu erkennen, ob diese bereits exportiert wurden
      result = new HashSet<>(nichtMehrAusgeschlosseneErfassungsgebiete);
    }

    for (Ergebniseingang ergebniseingang : ergebniseingaenge) {
      if (ergebniseingang.getEingangssequenznummer() > praesentationsexport.getLetzteEingangssequenznummer()) {
        result.add(ergebniseingang.getWahldurchfuehrungsgebiet());
      }
    }

    return new ArrayList<>(result);
  }

  private Praesentationsexport findOrCreatePraesentationsexport(PraesentationExportContext praesentationExportContext,
                                                                FileFormat fileFormat, Ergebnis ergebnis, Datei datei) {
    Stimmabgabeart zuExportierendeStimmabgabeart = Stimmabgabeart.GESAMT;
    Praesentationsexportart praesentationsexportart = Praesentationsexportart.INTERNET;
    Praesentationsexportausloeser praesentationsexportausloeser = praesentationExportContext.getPraesentationsexportausloeser();
    Praesentationsexport result;

    // ELECTMUC-369 wenn es mehrere praesentationsexporte gibt, den mit dem kleinsten PK nehmen
    List<Praesentationsexport> liste = praesentationsexportDAO.findByErgebnisAndArtAndAusloeserAndStimmabgabeart(ergebnis,
            praesentationsexportart, praesentationsexportausloeser, zuExportierendeStimmabgabeart);
    if (liste.isEmpty()) {
      result = legePraesentationsexportAn(ergebnis, datei, praesentationsexportart, zuExportierendeStimmabgabeart, praesentationsexportausloeser);
    } else {
      if (liste.size() > 1) {
        LOG.warn("Mehr als ein Praesentationsexport vorhanden: " + ergebnis + ", " + praesentationsexportart + ", "
                + praesentationsexportausloeser + ", " + zuExportierendeStimmabgabeart);
      }

      result = liste.stream().min(Comparator.comparing(Praesentationsexport::getPk)).orElse(liste.get(0));
      result.setDatei(datei);
    }


    return result;
  }

  private Praesentationsexport legePraesentationsexportAn(Ergebnis ergebnis, Datei datei, Praesentationsexportart praesentationsexportart,
                                                          Stimmabgabeart zuExportierendeStimmabgabeart, Praesentationsexportausloeser praesentationsexportausloeser) {
    Praesentationsexport praesentationsexport = new Praesentationsexport();
    praesentationsexport.setDatei(datei);
    praesentationsexport.setErgebnis(ergebnis);
    praesentationsexport.setPraesentationsexportart(praesentationsexportart);
    praesentationsexport.setLetzteEingangssequenznummer(INITIALE_NUMMER);
    praesentationsexport.setStimmabgabeart(zuExportierendeStimmabgabeart);
    praesentationsexport.setPraesentationsexportausloeser(praesentationsexportausloeser);
    praesentationsexportDAO.persist(praesentationsexport);
    return praesentationsexport;
  }

}
