
package de.ivu.elect.presentation.ergebniskonflikt;

import static org.apache.commons.lang3.StringUtils.isBlank;

import java.util.Collection;
import java.util.Date;
import java.util.Objects;

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

import de.ivu.elect.business.ergebnis.boundary.Ergebnisberechnung;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.ErgebnisKonfliktStatus;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonfliktCustomData;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonfliktProperties;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.boundary.PolitischeGruppeExtendedDAO;
import de.ivu.elect.business.kandidatur.boundary.KandidaturExtendedDAO;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.sitzberechnung.control.Sitzberechnungsalgorithmus;
import de.ivu.elect.business.sitzberechnung.control.SitzberechnungsalgorithmusFinder;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.business.wahlvorschlag.boundary.ListenverbindungExtendedDAO;
import de.ivu.elect.business.wahlvorschlag.boundary.WahlvorschlagExtendedDAO;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;

@OnlineHilfeId(value = "266", mehrfachVergebenOk = true)
public abstract class AbstractErgebnisKonfliktLoesenView<T extends ErgebnisKonfliktCustomData> extends AbstractErgebnisKonfliktEditView {

  private static final long serialVersionUID = 1L;

  @Inject
  protected WahlvorschlagExtendedDAO wahlvorschlagDAO;

  @Inject
  protected KandidaturExtendedDAO kandidaturDAO;

  @Inject
  protected ListenverbindungExtendedDAO listenverbindungDAO;

  @Inject
  protected PolitischeGruppeExtendedDAO politischeGruppeDAO;

  @Inject
  protected WahldurchfuehrungsgebietExtendedDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private Ergebnisberechnung ergebnisberechnung;

  @Inject
  private SitzberechnungsalgorithmusFinder sitzberechnungsalgorithmusFinder;

  protected AbstractErgebnisKonfliktLoesenView() {
    super();
  }

  @Override
  public String getViewId() {
    return getCustomData(getEntity()).getErgebnisKonfliktLoesungViewId();
  }

  protected boolean isErgebnisKonfliktGeloest() {
    return isEntitySet() && getEntity().isGeloest();
  }

  @Override
  protected boolean isGebietBearbeitenRechtPruefen() {
    return false;
  }

  public String getPageTitle() {
    return getMessage("ergebnis.konflikt.loesen.page.title");
  }

  public String getPageHeader() {
    String gebietName = getGebietName();

    if (isBlank(gebietName)) {
      return getMessage("ergebnis.konflikt.loesen.page.header");
    }

    return getMessage("ergebnis.konflikt.loesen.gebiet.page.header", gebietName);
  }

  public String getGebietName() {
    return formatGebietName(getGebiet());
  }

  @Nullable
  protected Gebiet getGebiet() {
    Gebiet result = null;

    for (Gebiet gebietAusLosoptionen : getErgebnisKonfliktGebiete()) {
      if (result == null) {
        result = gebietAusLosoptionen;
      } else if (!Objects.equals(gebietAusLosoptionen, result)) {
        return null; // ELECT-12143, Auswahl aus Listen eine Gruppe auf verschiedenen Gebiete...
      }
    }

    return result;
  }

  protected abstract Collection<Gebiet> getErgebnisKonfliktGebiete();

  @Override
  public void addProperties(FormBuilder formBuilder, ErgebnisKonflikt ergebnisKonflikt) {
    ErgebnisKonfliktProperties ergebnisKonfliktProperties = ergebnisKonflikt.getProperties();

    formBuilder.addProperty(ergebnisKonfliktProperties.getErgebnisKonfliktArtProperty());
    formBuilder.addProperty(ergebnisKonfliktProperties.getErgebnisKonfliktStatusProperty());
    formBuilder.addProperty(ergebnisKonfliktProperties.getKonfliktBeschreibungProperty());

    if (isErgebnisKonfliktGeloest()) {
      formBuilder.addProperty(ergebnisKonfliktProperties.getLoesungVonProperty());
      formBuilder.addProperty(ergebnisKonfliktProperties.getLoesungZeitpunktProperty());
      formBuilder.addProperty(ergebnisKonfliktProperties.getLoesungBeschreibungProperty());
    }

    // Alle bisherigen Properties sind immer readonly!
    formBuilder.globalReadonly();

    addErgebnisKonfliktLoesungProperties(formBuilder, ergebnisKonflikt);
  }

  protected abstract void addErgebnisKonfliktLoesungProperties(FormBuilder formBuilder, ErgebnisKonflikt ergebnisKonflikt);

  @Override
  @Redirect
  @UseCaseSecure(UseCasePermission.ERGEBNIS_KONFLIKT_EDIT)
  public String save() {
    ErgebnisKonflikt ergebnisKonflikt = getEntity();
    ergebnisKonflikt.setErgebnisKonfliktStatus(ErgebnisKonfliktStatus.MANUELL_ENTSCHIEDEN);

    updateErgebnisKonfliktLoesung(ergebnisKonflikt);

    String redirectViewId = super.save();

    updateErgebnis(ergebnisKonflikt.getErgebnis());

    return redirectViewId;
  }

  protected void updateErgebnisKonfliktLoesung(ErgebnisKonflikt ergebnisKonflikt) {
    ergebnisKonflikt.setLoesungBeschreibung(createErgebnisKonfliktLoesungBeschreibung(getCustomData(ergebnisKonflikt), messages));
    ergebnisKonflikt.setLoesungVon(getSelectedBenutzerKennung());
    ergebnisKonflikt.setLoesungZeitpunkt(new Date());
  }

  protected abstract String createErgebnisKonfliktLoesungBeschreibung(T ergebnisKonfliktCustomData, Messages messages);

  private void updateErgebnis(Ergebnis ergebnis) {
    Sitzberechnungsalgorithmus< ? > sitzberechnungsalgorithmus = sitzberechnungsalgorithmusFinder.getSitzberechnungsalgorithmus(ergebnis.getWahl().castTo(Wahldurchfuehrung.class).getEntity());
    ergebnisberechnung.aktualisiereErgebnis(ergebnis.getPk(), getMessage("ergebnis.berechnen.ausloeser.ergebnis.konflikt.bearbeitet"), sitzberechnungsalgorithmus.getDefaultKonfiguration());
  }

  protected T getCustomData(ErgebnisKonflikt ergebnisKonflikt) {
    return ergebnisKonflikt.getCustomData(getErgebnisKonfliktCustomDataClass());
  }

  protected abstract Class<T> getErgebnisKonfliktCustomDataClass();
}
