
package de.ivu.elect.dokumente.stimmeingabe;

import static java.util.Arrays.asList;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.dokumente.entity.DokumentVorlage;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeDocumentByErgebnisDatenExportContext;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeDocumentByErgebnisDatenExportObject;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeDocumentErgebnisDaten;
import de.ivu.elect.dokumente.CoreElectContext;

/**
 * Mapping mit ErgebnisDaten.
 *
 * @see AbstractWasStimmeingabeDocumentByErgebniseingangExportMapper für Mapping mit Ergebniseingang!
 */
public abstract class AbstractCoreStimmeingabeDocumentByErgebnisDatenExportMapper
    extends
      AbstractCoreStimmeingabeDocumentExportMapper<StimmeingabeDocumentByErgebnisDatenExportContext, StimmeingabeDocumentByErgebnisDatenExportObject>
    implements
      StimmeingabeDocumentByErgebnisDatenExportMapper {

  private static final int MAX_DOCUMENTS_PER_SINGLE_ODT_DOCUMENT = MAX_DOCUMENTS_PER_SINGLE_ODT_DOCUMENT_CAUSING_ODT_DOCUMENT_PER_ERFASSUNGSGEBIET_IN_SUBDIRECTORY_PER_GEBIET;

  protected AbstractCoreStimmeingabeDocumentByErgebnisDatenExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(StimmeingabeDocumentByErgebnisDatenExportContext context) {
    Ergebnis ergebnis = context.getErgebnis();

    return ergebnis != null && ergebnis.getWahl() != null && isAcceptFileType(context, getFileType());
  }

  private boolean isAcceptFileType(StimmeingabeDocumentByErgebnisDatenExportContext context, FileType fileType) {
    // ELECT-7091, es wird je ein Java-Dokument (bestehend aus mehreren Seiten) per Erfassungsgebiet erzeugt, daher count(Erfassungsgebiet) == count(Java-Dokument)!
    return !serializeOdtDocumentPerWurzelgebiet() || context.getErfassungsgebiete(gebietDAO).size() <= MAX_DOCUMENTS_PER_SINGLE_ODT_DOCUMENT;
  }

  @Override
  protected DokumentVorlage getDokumentVorlage(StimmeingabeDocumentByErgebnisDatenExportContext exportContext) {
    return exportContext.getDokumentVorlage();
  }

  @Override
  protected Gebiet findWahlgebiet(StimmeingabeDocumentByErgebnisDatenExportContext context, StimmeingabeDocumentByErgebnisDatenExportObject exportObject) {
    return findWahlgebiet(context.getErfassungsgebiete(gebietDAO));
  }

  protected Map<Gebiet, List<StimmeingabeDocument>> createDocumentsFuerStimmzettelgebietPerStimmzettelgebiet(StimmeingabeDocumentErgebnisDaten<Gebiet> ergebnisDaten, CoreElectContext coreElectContext,
      StimmeingabeDocumentByErgebnisDatenExportContext exportContext) {
    Map<Gebiet, List<StimmeingabeDocument>> result = new LinkedHashMap<>(); // ELECT-9621, Sortierung erhalten...

    StimmeingabeDocumentContext context = new StimmeingabeDocumentContext(coreElectContext, exportContext);

    for (Gebiet stimmzettelgebiet : exportContext.getStimmzettelgebiete()) {
      StimmeingabeDocument documentFuerStimmzettelgebiet = getStimmeingabeDocumentFactory().createDocumentFuerStimmzettelgebiet(context, stimmzettelgebiet, ergebnisDaten);

      result.put(stimmzettelgebiet, asList(documentFuerStimmzettelgebiet));
    }

    return result;
  }

  @Override
  protected Map<Gebiet, List<StimmeingabeDocument>> createDocumentsFuerErfassungsgebietPerUebergeordnetemGebiet(StimmeingabeDocumentContext stimmeingabeDocumentContext,
      StimmeingabeDocumentByErgebnisDatenExportContext exportContext, StimmeingabeDocumentByErgebnisDatenExportObject exportObject) {
    Map<Gebiet, List<StimmeingabeDocument>> result = new LinkedHashMap<>(); // ELECT-9621, Sortierung erhalten...

    List<Gebiet> erfassungsgebieteSorted = new ArrayList<>(exportContext.getErfassungsgebiete(gebietDAO));
    erfassungsgebieteSorted.sort(GEBIET_COMPARATOR);

    StimmeingabeDocumentErgebnisDaten<Gebiet> ergebnisDaten = exportObject.getErgebnisDaten();

    for (Gebiet erfassungsgebiet : erfassungsgebieteSorted) {
      Gebiet uebergeordnetesGebiet = erfassungsgebiet.getUebergeordnetesGebiet();
      StimmeingabeDocument documentFuerErfassungsgebiet = getStimmeingabeDocumentFactory().createDocumentFuerErfassungsgebiet(stimmeingabeDocumentContext, erfassungsgebiet, ergebnisDaten);

      result.computeIfAbsent(uebergeordnetesGebiet, x -> new ArrayList<>()).add(documentFuerErfassungsgebiet);
    }

    info("Erzeuge Dokumente mit Ergebnisdaten");

    return result;
  }
}
