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

import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang3.StringUtils.replaceIgnoreCase;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.business.wahl.control.AbstractNlExportArtefaktNachSystemExportstatusExportContext;
import de.ivu.elect.business.wahl.control.NlExportArtefaktNachSystemExportstatusExportObject;
import de.ivu.elect.exchange.ExportMapper;

public interface NlExportArtefaktNachSystemExportstatusExportMapper
    extends
      ExportMapper<NlExportArtefaktNachSystemExportstatusExportObject, AbstractNlExportArtefaktNachSystemExportstatusExportContext> {

  /**
   * @return Gibt true zurück, falls der Export UNABHÄNGIG VOM STATUS DES SYSTEMS (GEBIETSTATUS, WAHLPHASE) überhaupt möglich ist!
   *
   * @see NlExportArtefaktNachSystemExportstatusExportMapper#isAcceptSystemExportstatus
   */
  boolean isAcceptContextIgnoringSystemExportstatus(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  /**
   * @return Gibt true zurück, falls der Export ABHÄNGIG VOM STATUS DES SYSTEMS (GEBIETSTATUS, WAHLPHASE) aktuell möglich ist!
   *
   * @see NlExportArtefaktNachSystemExportstatusExportMapper#isAcceptContextIgnoringSystemExportstatus
   */
  boolean isAcceptSystemExportstatus(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  default String getFileFormatName() {
    return getFileFormat().getName();
  }

  boolean supportsBulkExportNachSystemExportstatus(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  default boolean requiresTargetFilesInSeparateBulkExportEntry(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return true; // ELECT-13502
  }

  default boolean requiresTargetFilesInSeparateDateiExport(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    // ELECTVAPP-1773
    //    return supportsTargetFilesSigning(context); // ELECTVAPP-794, ELECTVAPP-795
    return false;
  }

  boolean supportsTargetFilesSigning(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean supportsTargetFilesHashCode(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  List<FileType> getTargetFileTypes(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  default List<String> describeTargetFiles(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return describeTargetFiles(context, getTargetFileTypes(context), fileType -> createTargetFileName(context, fileType));
  }

  default List<String> describeTargetFiles(AbstractNlExportArtefaktNachSystemExportstatusExportContext context, List<FileType> targetFileTypes, Function<FileType, String> targetFileNameFct) {
    List<String> result = new ArrayList<>();

    if (targetFileTypes.size() > 2) { // ELECT-10764, "viele" Dateiendungen als Zusatz in einer Zeile auflisten...
      String fileExtensionsFormatted = targetFileTypes.stream() //
          .map(FileType::getFileExtension) //
          .map(StringUtils::lowerCase) //
          .collect(joining(", "));

      FileType fileType = targetFileTypes.get(0);
      String simpleFileName = replaceIgnoreCase(targetFileNameFct.apply(fileType), "." + fileType.getFileExtension(), "");

      result.add(simpleFileName + " (" + fileExtensionsFormatted + ")");
    } else {
      for (FileType fileType : targetFileTypes) {
        result.add(targetFileNameFct.apply(fileType));
      }
    }

    return result;
  }

  String createTargetFileName(AbstractNlExportArtefaktNachSystemExportstatusExportContext context, FileType fileType);

  void serialize(NlExportArtefaktNachSystemExportstatusExportObject exportObject, OutputStream os, AbstractNlExportArtefaktNachSystemExportstatusExportContext context,
      FileKonfiguration fileKonfiguration, boolean closeOutputStream) throws Exception;

  boolean requiresWahlbehoerdeWahlleiterName(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeAnschriftStrasseHausnummer(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeAnschriftPlz(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeDokumentErstelltAnschriftStrasseHausnummer(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeDokumentErstelltAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeDokumentErstelltAnschriftPlz(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlbehoerdeDokumentErstelltAm(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresGewaehltesGremiumDurchfuehrendesOrgan(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresGewaehltesGremiumAnschriftStrasseHausnummer(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresGewaehltesGremiumAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresGewaehltesGremiumAnschriftPlz(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungZuvorBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungAnschriftStrasseHausnummer(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungAnschriftPlz(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungEnde(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungFehlerVermutet(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungEinwaende(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungEinwaendeBemerkungen(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungUnterzeichner1Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungUnterzeichner1Rolle(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungUnterzeichner2Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlausschusssitzungUnterzeichner2Rolle(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresFristZuletztGesetztBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresFristZuletztGesetztEnde(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlvorschlagEinreichungAbgabefrist(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlvorschlagEinreichungAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlvorschlagEinreichungUnterzeichner1Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlvorschlagVeroeffentlichungBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlvorschlagVeroeffentlichungAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresWahlvorschlagVeroeffentlichungUnterzeichner1Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresEinwohnerzahlVeroeffentlichungId(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresEinwohnerzahlVeroeffentlichungDatum(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresKorrekturenStimmeingabenKopfzahlenWaehlerVorhanden(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresKorrekturenStimmeingabenKopfzahlenStimmzettelVorhanden(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresKorrekturenStimmeingabenKopfzahlenStimmzettelAbweichendVorhanden(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresKorrekturenStimmeingabenStimmenListenIds(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  boolean requiresKorrekturenErfassungsgebiete(AbstractNlExportArtefaktNachSystemExportstatusExportContext context);

  static List<FileType> sortFileTypesByOdtFirst(List<FileType> fileTypes) {
    List<FileType> result = new ArrayList<>();

    for (FileType fileType : fileTypes) {
      if (FileType.ODT.equals(fileType)) {
        result.add(0, fileType);
      } else {
        result.add(fileType);
      }
    }

    return result;
  }
}
