
package de.ivu.elect.presentation.stimmeingabe;

import static de.ivu.elect.jee.entity.EntityUtil.castTo;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

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

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

import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.stimmeingabe.boundary.AbstractStimmeingabePlausiKonfigurationSearchParameters;
import de.ivu.elect.business.stimmeingabe.boundary.ErgebniseingangKonfiguration;
import de.ivu.elect.business.stimmeingabe.boundary.StimmeingabePlausiKonfigurationSearch;
import de.ivu.elect.business.stimmeingabe.boundary.StimmeingabePlausiKonfigurationSearchParameters;
import de.ivu.elect.business.stimmeingabe.control.plausi.StimmeingabePlausiDefinitions;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiErgebniseingangsart;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiFehlerart;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiGebietsart;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiKonfiguration;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiKonfigurationConstants;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiStatus;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.BooleanFilterKriterium;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaEnumProperty;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.security.AbstractGebietSecurityFilter;

@OnlineHilfeId("727")
@ViewAccessScoped
@Named(AbstractStimmeingabePlausiKonfigurationSearchView.COMPONENT_NAME)
@View(viewId = AbstractStimmeingabePlausiKonfigurationSearchView.VIEW_ID, useCase = UseCasePermission.STIMMEINGABE_PLAUSI_SEARCH)
public class StimmeingabePlausiKonfigurationSearchView extends AbstractStimmeingabePlausiKonfigurationSearchView {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient ErgebniseingangKonfiguration ergebniseingangKonfiguration;

  @Inject
  private transient StimmeingabePlausiKonfigurationSearch search;

  @Inject
  @ConversationGroup(AbstractStimmeingabePlausiKonfigurationSearchParameters.class)
  protected transient StimmeingabePlausiKonfigurationSearchParameters searchParameters;

  public StimmeingabePlausiKonfigurationSearchView() {
    super();
  }

  @Nullable
  @PreConditionCheck
  public String checkPreCondition() {
    if (isStimmeingabePlausiDefinitionsAvailable()) {
      return null;
    }

    return getStartViewId();
  }

  @Override
  public int getDefaultPageSize() {
    return getPageSizeShowAll();
  }

  private boolean isStimmeingabePlausiDefinitionsAvailable() {
    return findStimmeingabePlausiDefinitions().isPresent();
  }

  @Override
  protected AbstractGebietSecurityFilter<StimmeingabePlausiKonfiguration> getGebietSecurityFilter() {
    return KEIN_GEBIET_SECURITY_FILTER;
  }

  /**
   * @deprecated To be removed...
   * @see StimmeingabePlausiKonfigurationSearchView#initSearchParametersByDefaults
   */
  @Deprecated
  @Override
  public void presetSearchParameters() {
    // To be removed...
  }

  @Override
  protected void initSearchParametersByDefaults() {
    super.initSearchParametersByDefaults();

    searchParameters.setErgebniseingangsart(StimmeingabePlausiErgebniseingangsart.VORLAEUFIG);

    if (isWahlSelected()) {
      Wahl wahl = getSelectedWahl();

      StimmeingabePlausiErgebniseingangsart stimmeingabePlausiErgebniseingangsart = StimmeingabePlausiErgebniseingangsart.UNBEKANNT;

      if (wahl != null && wahl.isInstanceOf(Wahldurchfuehrung.class)) {
        stimmeingabePlausiErgebniseingangsart = StimmeingabePlausiErgebniseingangsart.of(castTo(wahl, Wahldurchfuehrung.class).getErgebniseingangsart());
      }

      searchParameters.setErgebniseingangsart(stimmeingabePlausiErgebniseingangsart);
    }

    searchParameters.setGebietsart(StimmeingabePlausiGebietsart.URNENWAHLBEZIRK);

    findStimmeingabePlausiDefinitions().ifPresent(stimmeingabePlausiDefinitions -> {
      List<StimmeingabePlausiGebietsart> gebietsarten = new ArrayList<>(stimmeingabePlausiDefinitions.collectGebietsartenRelevant());

      if (!gebietsarten.isEmpty()) {
        searchParameters.setGebietsart(gebietsarten.iterator().next());
      }
    });
  }

  @Override
  public void addProperties(FormBuilder formBuilder) {
    List<StimmeingabePlausiErgebniseingangsart> ergebniseingangsarten = stream(StimmeingabePlausiErgebniseingangsart.values()) //
        .filter(ergebniseingangsart -> !ergebniseingangsart.isUnbekannt() && ergebniseingangKonfiguration.isErgebniseingangsartUnterstuetzt(getSelectedWahl(), ergebniseingangsart)) //
        .collect(toList());

    formBuilder.addProperty(new LambdaEnumProperty<>(getMessage(StimmeingabePlausiKonfigurationConstants.MESSAGE_KEY_PLAUSI_ERGEBNISART_EINZAHL), false, searchParameters::setErgebniseingangsart,
        searchParameters::getErgebniseingangsart, StimmeingabePlausiErgebniseingangsart.class, ergebniseingangsarten, true));

    findStimmeingabePlausiDefinitions().ifPresent(stimmeingabePlausiDefinitions -> {
      List<StimmeingabePlausiGebietsart> gebietsarten = new ArrayList<>(stimmeingabePlausiDefinitions.collectGebietsartenRelevant());

      if (gebietsarten.size() > 1) {
        formBuilder.addProperty(new LambdaEnumProperty<>(getMessage(StimmeingabePlausiKonfigurationConstants.MESSAGE_KEY_PLAUSI_GEBIETSART_EINZAHL), false, searchParameters::setGebietsart,
            searchParameters::getGebietsart, StimmeingabePlausiGebietsart.class, gebietsarten, true));
      }
    });

    List<StimmeingabePlausiFehlerart> fehlerarten = stream(StimmeingabePlausiFehlerart.values()) //
        .filter(fehlerart -> !fehlerart.isUnbekannt()) //
        .collect(toList());

    formBuilder.addProperty(new LambdaEnumProperty<>(getMessage(StimmeingabePlausiKonfigurationConstants.MESSAGE_KEY_PLAUSI_FEHLERART_EINZAHL), false, searchParameters::setFehlerart,
        searchParameters::getFehlerart, StimmeingabePlausiFehlerart.class, fehlerarten, true));

    formBuilder.addProperty(new LambdaEnumProperty<>(getMessage(StimmeingabePlausiKonfigurationConstants.MESSAGE_KEY_PLAUSI_STATUS_EINZAHL), false, searchParameters::setStatus,
        searchParameters::getStatus, StimmeingabePlausiStatus.class, asList(StimmeingabePlausiStatus.values()), true));

    formBuilder.addProperty(new LambdaEnumProperty<>(getMessage("stimmeingabe.plausi.konfiguration.search.parameter.default.overridden"), false,
        searchParameters::setStimmeingabePlausiKonfigurationDefaultOverriddenFilterKriterium, searchParameters::getStimmeingabePlausiKonfigurationDefaultOverriddenFilterKriterium,
        BooleanFilterKriterium.class, asList(BooleanFilterKriterium.values()), true));
  }

  protected Optional<StimmeingabePlausiDefinitions> findStimmeingabePlausiDefinitions() {
    return search.findStimmeingabePlausiDefinitions(searchParameters);
  }
}
