
package de.ivu.elect.presentation.stimmeingabe;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

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

import org.apache.deltaspike.core.api.scope.ConversationGroup;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietConversationSelect;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietPK;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.stimmeingabe.boundary.StimmeingabeListenkandidaturStimmenErfassenViewGruppeImGebietConversationQueue;
import de.ivu.elect.business.stimmeingabe.entity.AbstractStimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeListenkandidaturStimmen;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeListenkandidaturStimmenErfassenModel;
import de.ivu.elect.business.stimmen.boundary.StimmenartLabelGenerator;
import de.ivu.elect.business.wahl.boundary.WahlSessionSelect;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.presentation.redirect.Redirect;

public abstract class AbstractStimmeingabeListenkandidaturStimmenErfassenView extends AbstractStimmeingabeErfassenView {

  private static final long serialVersionUID = 1L;

  @Inject
  protected transient WahlSessionSelect wahlSessionSelect;

  @Inject
  protected transient GruppeImGebietConversationSelect gruppeImGebietConversationSelect;

  @Inject
  @ConversationGroup(StimmeingabeListenkandidaturStimmenErfassenViewGruppeImGebietConversationQueue.class)
  protected transient StimmeingabeListenkandidaturStimmenErfassenViewGruppeImGebietConversationQueue stimmeingabeListenkandidaturStimmenErfassenViewGruppeImGebietConversationQueue;

  @Inject
  protected transient StimmenartLabelGenerator stimmenartLabelGenerator;

  protected AbstractStimmeingabeListenkandidaturStimmenErfassenView() {
    super();
  }

  @Override
  public boolean isApplicable(@Nullable Wahl wahl) {
    return getStimmeingabeErfassenDescription().isApplicable(wahl);
  }

  @Override
  protected boolean isErfassungAufUnterseite() {
    return true;
  }

  public abstract String getParentViewId();

  @Override
  protected String checkPreConditionInternal() {
    if (!isGruppeImGebietSelected()) {
      addErrorMessage("stimmeingabe.listenkandidatur.erfassen.message.keine.gruppe.im.gebiet.gewaehlt");

      return getStimmeingabeErfassenViewId();
    }

    if (!getGruppeImGebiet().hatListeAufStimmzettelInUebergeordneterGebietshierarchie(getStimmeingabeErfassenContext().getWahlvorschlaege())) {
      addErrorMessage("stimmeingabe.listenkandidatur.erfassen.message.gruppe.im.gebiet.ohne.liste.auf.stimmzettel.gewaehlt");

      return getStimmeingabeErfassenViewId();
    }

    return null;
  }

  public String getStimmeingabenListenkandidaturStimmenListenstimmeBezeichnung() {
    return stimmenartLabelGenerator.getListenstimmeBezeichnungPlural(getGebiet());
  }

  @Override
  protected void gebietWechselt(Gebiet neuesGebiet) {
    // nothing to do

    // HINT: nicht die gewählte GruppeImGebiet zurücksetzen -- sonst können wir deren Änderung später nicht mehr feststellen und behandeln
  }

  private boolean isWahlSelected() {
    return wahlSessionSelect.isSelected();
  }

  public boolean isGruppeImGebietSelected() {
    return gruppeImGebietConversationSelect.isSelected();
  }

  public GruppeImGebiet getGruppeImGebiet() {
    return gruppeImGebietConversationSelect.getEntity();
  }

  public String getGruppeBezeichnung() {
    return getStimmeingabeListenkandidaturStimmenErfassenLabelGenerator().getListenkandidaturStimmenBezeichnung(getEntityAufStimmzettelDaten(), getGruppeImGebiet(), getErgebniseingangsart(),
        getGruppenImGebiet());
  }

  public String getGruppeKennung() {
    return getStimmeingabeListenkandidaturStimmenErfassenLabelGenerator().getListenkandidaturStimmenKennung(getEntityAufStimmzettelDaten(), getGruppeImGebiet(), getErgebniseingangsart(),
        getGruppenImGebiet());
  }

  public List<StimmeingabeListenkandidaturStimmen> getStimmeingabenListenStimmen() {
    List<StimmeingabeListenkandidaturStimmen> result = new ArrayList<>();

    StimmeingabeListenkandidaturStimmen stimmeingabeListenStimmen = getStimmeingabeListenStimmen();

    if (stimmeingabeListenStimmen != null) {
      result.add(stimmeingabeListenStimmen);
    }

    return result;
  }

  @Nullable
  public StimmeingabeListenkandidaturStimmen getStimmeingabeListenStimmen() {
    return getStimmeingabeListenkandidaturStimmenErfassenModel().getListenStimmen();
  }

  public List<StimmeingabeListenkandidaturStimmen> getStimmeingabenListenkandidaturStimmen() {
    return getStimmeingabeListenkandidaturStimmenErfassenModel().getListenkandidaturStimmen();
  }

  public List<StimmeingabeListenkandidaturStimmen> getStimmeingabenListenkandidaturStimmenZwischensummen() {
    return getStimmeingabeListenkandidaturStimmenErfassenModel().getListenkandidaturZwischensummen();
  }

  @Nullable
  public StimmeingabeListenkandidaturStimmen getStimmeingabeListenkandidaturStimmenGesamt() {
    return getStimmeingabeListenkandidaturStimmenErfassenModel().getListenkandidaturStimmenGesamt();
  }

  public StimmeingabeListenkandidaturStimmenErfassenModel getStimmeingabeListenkandidaturStimmenErfassenModel() {
    return getStimmeingabeListenkandidaturStimmenErfassenModel(getGruppeImGebiet());
  }

  @Override
  protected Collection<Stimmeingabe> getStimmeingabenFuerDiesenView() {
    return new HashSet<>(getStimmeingabeListenkandidaturStimmenErfassenModel().getAllStimmeingaben());
  }

  @Override
  @Redirect
  @UseCaseSecure(UseCasePermission.STIMMEINGABE_CREATE)
  public String save() {
    Collection<Stimmeingabe> stimmeingabenFuerDiesenView = getStimmeingabenFuerDiesenView();

    super.save();

    if (containsStimmeingabefehler(stimmeingabenFuerDiesenView)) {
      return getViewId();
    }

    return clearGruppeImGebietSelectedAndGoBack();
  }

  private boolean containsStimmeingabefehler(Collection<Stimmeingabe> stimmeingaben) {
    return stimmeingaben.stream().anyMatch(AbstractStimmeingabe::hasStimmeingabefehler);
  }

  @Override
  @Redirect
  public String cancel() {
    return clearGruppeImGebietSelectedAndGoBack();
  }

  private String clearGruppeImGebietSelectedAndGoBack() {
    clearGruppeImGebietSelected();
    return goBack(getParentViewId());
  }

  private void clearGruppeImGebietSelected() {
    gruppeImGebietConversationSelect.clearEntity();
  }

  @Override
  protected String getStimmeingabeBezug(Stimmeingabe stimmeingabe) {
    return getStimmeingabeListenkandidaturStimmenErfassenLabelGenerator().getListenkandidaturStimmenStimmeingabeKennung(getEntityAufStimmzettelDaten(), stimmeingabe, getGruppenImGebiet());
  }

  public boolean isBtnSaveAndNaechsteListenkandidaturErfassenRendered() {
    return hasPermission(UseCasePermission.STIMMEINGABE_CREATE) && !isErfassungGesperrt();
  }

  public boolean isBtnSaveAndNaechsteListenkandidaturErfassenDisabled() {
    return !isWahlSelected()
        && (!isGebietSelected() || !getGebiet().isEingabeMoeglich(getErgebniseingangsart().korrespondierendeErgebnisart(), getErgebniseingangsherkunft(), getEingangsherkunftIgnorieren()));
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.STIMMEINGABE_CREATE)
  public String saveAndNaechsteListenkandidaturErfassen() {
    Collection<Stimmeingabe> stimmeingabenFuerDiesenView = getStimmeingabenFuerDiesenView();

    super.save();

    if (containsStimmeingabefehler(stimmeingabenFuerDiesenView)) {
      return getViewId();
    }

    GruppeImGebietPK naechsteStimmeingabeGruppeImGebietPK = getNaechsteGruppeImGebiet();

    clearGruppeImGebietSelected();

    if (naechsteStimmeingabeGruppeImGebietPK == null) {
      return goBack(getParentViewId());
    }

    gruppeImGebietConversationSelect.setEntity(naechsteStimmeingabeGruppeImGebietPK);

    return getViewId();
  }

  @Redirect
  public String naechsteListenkandidaturErfassen() {
    Collection<Stimmeingabe> stimmeingabenFuerDiesenView = getStimmeingabenFuerDiesenView();

    reset();

    if (containsStimmeingabefehler(stimmeingabenFuerDiesenView)) {
      return getViewId();
    }

    GruppeImGebietPK naechsteStimmeingabeGruppeImGebietPK = getNaechsteGruppeImGebiet();

    clearGruppeImGebietSelected();

    if (naechsteStimmeingabeGruppeImGebietPK == null) {
      return goBack(getParentViewId());
    }

    gruppeImGebietConversationSelect.setEntity(naechsteStimmeingabeGruppeImGebietPK);

    return getViewId();
  }

  @Nullable
  protected GruppeImGebietPK getNaechsteGruppeImGebiet() {
    return stimmeingabeListenkandidaturStimmenErfassenViewGruppeImGebietConversationQueue.getNachfolgerVon(getGruppeImGebiet());
  }

  @Override
  protected boolean isErgebniseingangsartWechselnUnterstuetzt() {
    return false; // erstmal nicht bei Listenkandidaturstimmen TODO ELECT-8163
  }
}
