
package de.ivu.elect.presentation.gruppeimgebiet;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.inject.Inject;
import javax.inject.Named;

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

import de.ivu.elect.business.gebietsbaum.boundary.GebietSelectChangeEvent;
import de.ivu.elect.business.gebietsbaum.boundary.GebietSessionSelect;
import de.ivu.elect.business.gruppeimgebiet.boundary.AbstractGruppeImGebietSearchParameters;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietChangeEvent;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietConversationStore;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietEdit;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietSearch;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietSearchParameters;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.security.control.ElectCommonPrincipal;
import de.ivu.elect.business.wahl.boundary.WahlSessionSelect;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.AdvancedDynaFormModel;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.jee.presentation.view.AbstractView;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.gruppe.GruppeSchluesselFormatter;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.security.GebietSecurity;
import de.ivu.elect.presentation.stimmzettel.EntityAufStimmzettelReihenfolgeEditView;

@RequestScoped
@OnlineHilfeId("350")
@Named(GruppeImGebietReihenfolgeEditView.COMPONENT_NAME)
@View(viewId = GruppeImGebietReihenfolgeEditView.VIEW_ID, useCase = UseCasePermission.GRUPPE_IM_GEBIET_POSITIONEN_BEARBEITEN)
@UseCaseSecure(UseCasePermission.GRUPPE_IM_GEBIET_POSITIONEN_BEARBEITEN)
public class GruppeImGebietReihenfolgeEditView extends AbstractView implements EntityAufStimmzettelReihenfolgeEditView {

  private static final long serialVersionUID = 1L;

  private static final String FALLBACK_PARENT_VIEW_ID = GruppeImGebietSearchView.VIEW_ID;

  public static final String VIEW_ID = "/gruppeimgebiet/gruppe-im-gebiet-reihenfolge-edit.xhtml";

  public static final String COMPONENT_NAME = "gruppeImGebietReihenfolgeEditView";

  @Inject
  private transient ElectCommonPrincipal principal;

  @Inject
  private transient WahlSessionSelect wahlSessionSelect;

  @Inject
  private transient GebietSessionSelect gebietSessionSelect;

  @Inject
  private transient RequestHandlerGruppeImGebietReihenfolgeEditView requestHandler;

  @Inject
  private transient GruppeImGebietEdit gruppeImGebietEdit;

  @Inject
  @ConversationGroup(GruppeImGebietConversationStore.class)
  private transient GruppeImGebietConversationStore conversationStore;

  @Inject
  private transient GruppeImGebietSearch gruppeImGebietSearch;

  @Inject
  @ConversationGroup(AbstractGruppeImGebietSearchParameters.class)
  private transient GruppeImGebietSearchParameters searchParameters;

  @Inject
  private transient GebietSecurity gebietSecurity;

  @Inject
  private transient GruppeImGebietChangeEvent gruppeImGebietChangeEvent;

  @Inject
  private transient GruppeSchluesselFormatter gruppeSchluesselFormatter;

  private transient Boolean alleReihenfolgenVorgegeben = null;

  private List<GruppeImGebiet> searchResult;

  public GruppeImGebietReihenfolgeEditView() {
    super();
  }

  @PreConditionCheck
  public String checkPreCondition() {
    if (!gebietSessionSelect.isSelected() || !gebietSessionSelect.getEntity().isWahlOderDirektwahlOderListenwahlgebietOderHatEntprechendesUntergebiet()) {
      return cancel();
    }

    return null;
  }

  @Override
  public void preRenderView() {
    if (isAlleReihenfolgenVorgegeben()) {
      addWarningMessage("gruppenreihenfolge.edit.alle.positionen.vorgegeben");
    }
  }

  public boolean isAlleReihenfolgenVorgegeben() {
    if (alleReihenfolgenVorgegeben == null) {
      alleReihenfolgenVorgegeben = getSearchResult().stream().allMatch(g -> g.getVorgegebenePosition() != null);
    }
    return alleReihenfolgenVorgegeben;
  }

  public boolean isStimmenAnzeigen() {
    return false;
  }

  public void onGebietSelectChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) GebietSelectChangeEvent event) {
    resetSearchResult();
  }

  public void onGruppeImGebietChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) GruppeImGebietChangeEvent event) {
    resetSearchResult();
  }

  public List<GruppeImGebiet> getSearchResult() {
    requestHandler.nothing(); // ELECT-248
    if (searchResult == null) {
      searchResult = gruppeImGebietSearch.getSearchResultOhneUebrigeImGebiet(searchParameters);
    }
    return searchResult;
  }

  public void setSearchResult(List<GruppeImGebiet> searchResult) {
    this.searchResult = searchResult;
  }

  public void resetSearchResult() {
    if (searchResult != null) {
      searchResult = null;
    }
  }

  private boolean isBearbeitenAufGebietErlaubt() {
    return gebietSecurity.getBearbeitenGebietSecurity().isRechtVorhanden(gebietSessionSelect.getEntity());
  }

  public boolean isPanelHintRendered() {
    return getWahl().getWahlart().getGruppenreihenfolgeVorgegeben();
  }

  @Override
  public boolean isBtnSaveRendered() {
    return hasPermission(UseCasePermission.GRUPPE_IM_GEBIET_POSITIONEN_BEARBEITEN) && isBearbeitenAufGebietErlaubt() && !isAlleReihenfolgenVorgegeben();
  }

  @Override
  public String getBtnSaveLabel() {
    return getMessage("reihenfolge.edit.action.save.nur.gebiet");
  }

  @Override
  @Redirect
  @UseCaseSecure(UseCasePermission.GRUPPE_IM_GEBIET_POSITIONEN_BEARBEITEN)
  public String save() {
    return savePositionen(false);
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.GRUPPE_IM_GEBIET_POSITIONEN_BEARBEITEN)
  public String saveUntergebiete() {
    return savePositionen(true);
  }

  private String savePositionen(boolean untergebiete) {
    boolean konsistent = gruppeImGebietEdit.positionenSetzenUndSpeichern(getSearchResult(), untergebiete);
    gruppeImGebietChangeEvent.sendChangeEvent();
    searchResult = null; // neu einlesen
    if (konsistent) {
      getMessages().addInfoMessage("entity.create.action.save.success.message", getMessage("entity.einzahl.GRUPPENREIHENFOLGE"));
    } else {
      getMessages().addWarnMessage("gruppenreihenfolge.inkonsistent.nach.aenderung");
    }

    getMessages().addInfoMessage("gruppenreihenfolge.untergebiete.hinweis");

    conversationStore.close();

    return goBack(FALLBACK_PARENT_VIEW_ID);
  }

  @Override
  public boolean isBtnCancelRendered() {
    return true;
  }

  @Override
  @Redirect
  public String cancel() {
    conversationStore.close();

    return goBack(FALLBACK_PARENT_VIEW_ID);
  }

  @Override
  public boolean isBtnResetRendered() {
    return !isAlleReihenfolgenVorgegeben();
  }

  @Override
  @Redirect
  public String reset() {
    conversationStore.close();
    return VIEW_ID;
  }

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

  private boolean hasPermission(UseCasePermission permission) {
    return principal.hasUseCasePermission(permission);
  }

  public String getGruppeSchluessel(GruppeImGebiet gruppeImGebiet) {
    return gruppeSchluesselFormatter.getSchluessel(gruppeImGebiet.getGruppe());
  }

  @Override
  public AdvancedDynaFormModel getModel() {
    return null;
  }

  @RequestScoped
  public static class RequestHandlerGruppeImGebietReihenfolgeEditView {

    @View
    @Inject
    GruppeImGebietReihenfolgeEditView reihenfolgeEditView;

    @PostConstruct
    public void init() {
      reihenfolgeEditView.resetSearchResult();
    }

    public void nothing() {
      // nichts zu tun
    }
  }

  public boolean isGruppeImGebietHatDirektkandidatColumnAnzeigen() {
    return getWahl().isWahlMitDirektkandidatengebieten();
  }

  private Wahl getWahl() {
    return wahlSessionSelect.getEntity();
  }

  public boolean isGruppeImGebietHatListeColumnAnzeigen() {
    return getWahl().isWahlMitListengebieten();
  }

  public String getNameAufGebietColumnWidth() {
    if (!getWahl().isWahlMitDirektkandidatengebieten()) {
      return "54%";
    }
    return "44%";
  }

  public boolean isVorgegebenePositionVorhanden() {
    return getSearchResult().stream().anyMatch(gruppeImGebiet -> gruppeImGebiet.getVorgegebenePosition() != null);
  }

  @Override
  public String getStyleClass() {
    return "reihenfolge-edit";
  }
}
