
package de.ivu.elect.was.exchange.ergebnis.eml;

import java.io.Serializable;
import java.util.List;
import java.util.function.Supplier;

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

import de.ivu.elect.EmlExportMapper;
import de.ivu.elect.business.CurrentCustomer;
import de.ivu.elect.business.ergebnis.boundary.NlErgebniseingabestatuswechelPruefer;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportContext;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportObject;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.boundary.NlGebietDarstellungNummerFormatter;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.security.Customer;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.nl.eml.readable.AbstractEmlElectionWrapper;
import de.ivu.elect.nl.eml.readable.ManagingAuthorityWrapper;
import de.ivu.elect.presentation.ergebnis.exchange.NlErgebnisExportView;
import de.ivu.elect.was.exchange.ergebnis.ErgebnisExportMapper;
import de.ivu.elect.was.exchange.wahl.EmlCommonMapper;

public abstract class AbstractEml5xxErgebnisExportMapper implements Serializable, ErgebnisExportMapper, EmlExportMapper {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient NlErgebniseingabestatuswechelPruefer nlErgebniseingabestatuswechelPruefer;

  @Inject
  private transient CurrentCustomer currentCustomer;

  @Inject
  private transient WahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient Messages messages;

  @Inject
  private transient EmlCommonMapper emlCommonMapper;

  @Inject
  private transient NlGebietDarstellungNummerFormatter nlGebietDarstellungNummerFormatter;

  public AbstractEml5xxErgebnisExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(ErgebnisExportContext context) {
    return context.getWahl() != null && isWahlebenePassend(context.getWahl()) && isGebietAuswahlNotwendigUndVorhanden(context) && isErgebnisVorhandenWennNotwendig(context.getErgebnis());
  }

  private boolean isErgebnisVorhandenWennNotwendig(Ergebnis ergebnis) {
    return !isErgebnisNotwendig() || isErgebnisVorhanden(ergebnis);
  }

  protected boolean isErgebnisVorhanden(Ergebnis ergebnis) {
    return nlErgebniseingabestatuswechelPruefer.isErgebnisAuswertungMoeglich(ergebnis);
  }

  protected abstract boolean isErgebnisNotwendig();

  protected boolean isWahlebenePassend(Wahl wahl) {
    boolean isPSB = isPSB(wahl);
    boolean isHSB = isHSB(wahl);
    boolean isCSB = isCSB(wahl);

    if (isPsbNotwendig() && (!isPSB || isHSB || isCSB)) {
      return false;
    }

    if (isHsbNotwendig() && (!isHSB || isCSB)) {
      return false;
    }

    if (isCsbNotwendig() && !isCSB) {
      return false;
    }

    return true;
  }

  protected boolean isPSB(Wahl wahl) {
    return NlWahlart.isWasPSB(wahl, getCustomer());
  }

  protected abstract boolean isPsbNotwendig();

  protected boolean isHSB(Wahl wahl) {
    return NlWahlart.isWasHSB(wahl, getCustomer());
  }

  protected abstract boolean isHsbNotwendig();

  protected boolean isCSB(Wahl wahl) {
    return NlWahlart.isWasCSB(wahl, getCustomer());
  }

  protected abstract boolean isCsbNotwendig();

  protected boolean isGebietAuswahlNotwendigUndVorhanden(ErgebnisExportContext context) {
    return !isGebietAuswahlNotwendig() || isGebietAusgewaehlt(context);
  }

  private boolean isGebietAusgewaehlt(ErgebnisExportContext context) {
    return getAusgewaehltesGebietPK(context) != null;
  }

  protected abstract boolean isGebietAuswahlNotwendig();

  protected abstract boolean isErfassungsgebietAuswahlNotwendig();

  @Nullable
  protected abstract Wahldurchfuehrungsgebiet bestimmeGebietFuerDaten(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context);

  protected Wahldurchfuehrungsgebiet bestimmeOberstesGebiet(ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    return ergebnisExportObject.getErgebnisDaten().getWurzelgebiet();
  }

  @Nullable
  protected GebietPK getAusgewaehltesGebietPK(ErgebnisExportContext context) {
    GebietPK gebietPK = context.get(NlErgebnisExportView.NL_ERGEBNIS_EXPORT_CONTEXT_PARAM_SELECTED_GEBIET_PK, GebietPK.class);

    if (gebietPK != null && isErfassungsgebietAuswahlNotwendig()) {
      if (!wahldurchfuehrungsgebietDAO.findByPrimaryKey(gebietPK).isErfassungsgebiet()) {
        return null;
      }
    }

    return gebietPK;
  }

  protected void mappeWahldaten(ErgebnisExportObject ergebnisExportObject, AbstractEmlElectionWrapper emlElectionWrapper, Gebiet gebiet, Supplier<List<Gebiet>> alleGebiete) {
    emlCommonMapper.mappeWahldaten(ergebnisExportObject.getErgebnisDaten().getWahl(), emlElectionWrapper, gebiet, alleGebiete);
  }

  protected void fillManagingAuthority(ManagingAuthorityWrapper managingAuthority, ErgebnisExportObject ergebnisExportObject, ErgebnisExportContext context) {
    fillManagingAuthority(managingAuthority, bestimmeGebietFuerDaten(ergebnisExportObject, context), bestimmeOberstesGebiet(ergebnisExportObject, context),
        nlGebietDarstellungNummerFormatter,  getAuthorityIdPrefix(ergebnisExportObject),
        createdByAuthorityIdPrefix(ergebnisExportObject));
  }

  protected abstract String getAuthorityIdPrefix(ErgebnisExportObject ergebnisExportObject);

  protected abstract String createdByAuthorityIdPrefix(ErgebnisExportObject ergebnisExportObject);

  protected String getMessage(String msgKey, Object... params) {
    return getMessages().getMessageForMessageKey(msgKey, params);
  }

  protected Messages getMessages() {
    return messages;
  }

  protected Customer getCustomer() {
    return currentCustomer.getCustomer();
  }
}
