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

import java.io.OutputStream;
import java.util.Collection;

import javax.inject.Inject;

import de.ivu.elect.business.ergebnis.boundary.ErgebnisDAO;
import de.ivu.elect.business.ergebnis.boundary.NlErgebniseingabestatuswechelPruefer;
import de.ivu.elect.business.ergebnis.control.NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.business.security.Customer;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingabestatus;
import de.ivu.elect.business.wahl.control.AbstractNlExportArtefaktNachSystemExportstatusExportContext;
import de.ivu.elect.business.wahl.control.NlExportArtefaktNachSystemExportstatusExportObject;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.core.exchange.wahl.AbstractNlExportArtefaktNachSystemExportstatusExportMapper;

public abstract class AbstractNlWasExportArtefaktNachGebietErgebniseingabestatusExportMapper extends AbstractNlExportArtefaktNachSystemExportstatusExportMapper {

  @Inject
  private transient ErgebnisDAO ergebnisDAO;

  @Inject
  private transient NlErgebniseingabestatuswechelPruefer nlErgebniseingabestatuswechelPruefer;

  protected AbstractNlWasExportArtefaktNachGebietErgebniseingabestatusExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return isAcceptContextIgnoringSystemExportstatus(context);
  }

  @Override
  public boolean isAcceptContextIgnoringSystemExportstatus(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    if (context instanceof NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext) {
      return isAcceptContextIgnoringSystemExportstatus((NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext) context);
    }

    return false;
  }

  protected boolean isAcceptContextIgnoringSystemExportstatus(NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext context) {
    Ergebnis ergebnis = getErgebnisDAO().attach(context.getErgebnis());

    if (ergebnis == null) {
      return false;
    }

    Wahl wahl = ergebnis.getWahl();

    if (wahl == null) {
      return false;
    }

    Customer customer = getCustomer();

    return isAcceptWahlart(wahl, customer) && isAcceptWahlebene(wahl, customer) && isAcceptWahlergebniserfassung(wahl, customer)
        && context.getErgebniseingabestatusExported().map(this::isAcceptErgebniseingabestatus).orElse(true);
  }

  protected boolean isAcceptWahlart(Wahl wahl, Customer customer) {
    return collectWahlartenAccepted().stream().anyMatch(wahlart -> wahlart.equalsWahlart(wahl));
  }

  protected abstract Collection<NlWahlart> collectWahlartenAccepted();

  protected abstract boolean isAcceptWahlebene(Wahl wahl, Customer customer);

  protected boolean isAcceptWahlergebniserfassung(Wahl wahl, Customer customer) {
    return true; // ELECT-9953
  }

  protected boolean isAcceptErgebniseingabestatus(Ergebniseingabestatus ergebniseingabestatus) {
    return collectErgebniseingabestatusAccepted().contains(ergebniseingabestatus);
  }

  protected abstract Collection<Ergebniseingabestatus> collectErgebniseingabestatusAccepted();

  @Override
  public boolean isAcceptSystemExportstatus(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    if (context instanceof NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext) {
      return isAcceptSystemExportstatus((NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext) context);
    }

    return false;
  }

  protected boolean isAcceptSystemExportstatus(NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext context) {
    Ergebnis ergebnis = getErgebnisDAO().attach(context.getErgebnis());

    if (ergebnis == null) {
      return false;
    }

    Wahl wahl = ergebnis.getWahl();

    if (wahl == null) {
      return false;
    }

    return nlErgebniseingabestatuswechelPruefer.isErgebnisExportMoeglich(ergebnis, collectErgebniseingabestatusAccepted());
  }

  @Override
  public boolean requiresGewaehltesGremiumDurchfuehrendesOrgan(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-12872, (bisher) Benoemingsbrief spezifisch...
  }

  @Override
  public boolean requiresFristZuletztGesetztBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresFristZuletztGesetztEnde(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlausschusssitzungUnterzeichner1Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlausschusssitzungUnterzeichner1Rolle(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlausschusssitzungUnterzeichner2Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlausschusssitzungUnterzeichner2Rolle(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlvorschlagEinreichungAbgabefrist(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlvorschlagEinreichungAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlvorschlagEinreichungUnterzeichner1Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlvorschlagVeroeffentlichungBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlvorschlagVeroeffentlichungAnschriftOrt(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlvorschlagVeroeffentlichungUnterzeichner1Name(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // WUS-spezifisch...
  }

  @Override
  public boolean requiresWahlausschusssitzungZuvorBeginn(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-15281, nur P 1f-1-spezifisch...
  }

  @Override
  public boolean requiresWahlausschusssitzungFehlerVermutet(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECTVAPP-2133, nur O 7-spezifisch...
  }

  @Override
  public boolean requiresEinwohnerzahlVeroeffentlichungId(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-13551, nur Eerste Kamer U16-spezifisch...
  }

  @Override
  public boolean requiresEinwohnerzahlVeroeffentlichungDatum(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-13551, nur Eerste Kamer U16-spezifisch...
  }

  @Override
  public boolean requiresKorrekturenStimmeingabenKopfzahlenWaehlerVorhanden(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-15235, nur Na 14-1-spezifisch...
  }

  @Override
  public boolean requiresKorrekturenStimmeingabenKopfzahlenStimmzettelVorhanden(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-15235, nur Na 14-1-spezifisch...
  }

  @Override
  public boolean requiresKorrekturenStimmeingabenKopfzahlenStimmzettelAbweichendVorhanden(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-15235, nur Na 14-1-spezifisch...
  }

  @Override
  public boolean requiresKorrekturenStimmeingabenStimmenListenIds(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-15235, nur Na 14-1-spezifisch...
  }

  @Override
  public boolean requiresKorrekturenErfassungsgebiete(AbstractNlExportArtefaktNachSystemExportstatusExportContext context) {
    return false; // ELECT-15560, nur Na 31-1- und Na 31-2-spezifisch...
  }

  @Override
  public void serialize(NlExportArtefaktNachSystemExportstatusExportObject exportObject, OutputStream os, AbstractNlExportArtefaktNachSystemExportstatusExportContext context,
      FileKonfiguration fileKonfiguration, boolean closeOutputStream) throws Exception {
    if (context instanceof NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext) {
      serialize(exportObject, os, (NlWasErgebnisArtefaktNachGebietErgebniseingabestatusExportContext) context, fileKonfiguration, closeOutputStream);
    }
  }

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

  protected ErgebnisDAO getErgebnisDAO() {
    return ergebnisDAO;
  }
}
