
package de.ivu.elect.presentation.statistik;

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

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.boundary.GebietSelectChangeEvent;
import de.ivu.elect.business.statistik.boundary.StatistikLaufExtendedDAO;
import de.ivu.elect.business.statistik.control.AbstractStatistikSearch;
import de.ivu.elect.business.statistik.control.AbstractStatistikSearchParameters;
import de.ivu.elect.business.statistik.entity.StatistikLauf;
import de.ivu.elect.business.statistik.entity.StatistikSearchEntity;
import de.ivu.elect.business.wahl.boundary.WahlExtendedDAO;
import de.ivu.elect.business.wahl.boundary.WahlSelectChangeEvent;
import de.ivu.elect.business.wahl.boundary.WahlterminSelectChangeEvent;
import de.ivu.elect.jee.entity.EagerLoadingCollector;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.presentation.AbstractElectSearchView;
import de.ivu.elect.presentation.security.AbstractGebietSecurityFilter;
import de.ivu.elect.presentation.statistik.table.AbstractStatistikSearchColumnBuilder;
import de.ivu.elect.presentation.wahl.form.LambdaWahlSelectOneMenuProperty;

public abstract class AbstractStatistikSearchView<T extends StatistikSearchEntity, SP extends AbstractStatistikSearchParameters> extends AbstractElectSearchView<T> {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient StatistikLaufExtendedDAO statistikLaufExtendedDAO;

  @Inject
  private transient WahlExtendedDAO wahlExtendedDAO;

  public AbstractStatistikSearchView() {
    super();
  }

  @Override
  @PostConstruct
  public void init() {
    getSearchParameters().reset(); // alle Statistiken teilen sich die selbe Instanz der Suchparameter => zurücksetzen

    super.init();
  }

  @Nullable
  @PreConditionCheck
  public String checkCondition() {
    if (!isWahlterminSelected() && !isWahlSelected() || !isGebietSelected()) {
      return getStartViewId();
    }

    return null;
  }

  @Override
  public void addProperties(FormBuilder formBuilder) {
    formBuilder.addProperty(new StatistikLaufSelectOneMenuProperty(getStatistikLaeufe(), getSearchParameters()::setStatistikLauf, getSearchParameters()::getStatistikLauf));

    formBuilder.addProperty(new LambdaWahlSelectOneMenuProperty(wahlExtendedDAO, getSelectedWahltermin().getWahlenSortiertNachPosition(), wahl -> wahl.getWahlart().getName(),
        getSearchParameters()::setWahl, getSearchParameters()::getWahl));
  }

  @Override
  protected List<T> performSearch() {
    return getSearch().getSearchResult(getSearchParameters(), getEagerLoadingCollector());
  }

  public EagerLoadingCollector<T> getEagerLoadingCollector() {
    EagerLoadingCollector<T> result = new EagerLoadingCollector<>();
    getColumnBuilder().collectEagerLoadings(result);
    return result;
  }

  @Override
  public void resetSearchResult() {
    super.resetSearchResult();
    getColumnBuilder().forceInit(); // Spalten teilweise von Suchparametern abhängig => neu initialisieren
  }

  public abstract AbstractStatistikSearchColumnBuilder<T> getColumnBuilder();

  protected abstract AbstractStatistikSearch<T, SP> getSearch();

  @Override
  protected AbstractGebietSecurityFilter<T> getGebietSecurityFilter() {
    return AbstractGebietSecurityFilter.createKeinFilter();
  }

  @Override
  public void presetSearchParameters() {
    getStatistikLaeufe().stream().findFirst().ifPresent(getSearchParameters()::setStatistikLauf);

    getColumnBuilder().forceInit(); // Spalten teilweise von Suchparametern abhängig => neu initialisieren
  }

  protected List<StatistikLauf> getStatistikLaeufe() {
    List<StatistikLauf> alleLaeufe = new ArrayList<>();

    if (getSelectedWahl() != null) {
      alleLaeufe = statistikLaufExtendedDAO.findByWahl(getSelectedWahl());
    } else if (getSelectedWahltermin() != null) {
      alleLaeufe = statistikLaufExtendedDAO.findByWahlterminNichtWahl(getSelectedWahltermin());
    }

    alleLaeufe.sort((v, u) -> u.getZeitpunktDesLaufs().compareTo(v.getZeitpunktDesLaufs()));

    return alleLaeufe;
  }

  @Override
  public SP getSearchParameters() {
    SP result = getStatistikSearchParameters();
    result.setGebiet(getSelectedGebiet());

    return result;
  }

  @Override
  public String reset() {
    getSearchParameters().setStatistikLauf(null);
    getSearchParameters().setGebiet(null);

    return super.reset();
  }

  protected abstract SP getStatistikSearchParameters();

  // ELECT-2231    ELECT-2250
  /*
   * searchParameters sind von der zur Bearbeitung ausgewählten Wahl abhängig.
   */
  public void onWahlSelectChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) WahlSelectChangeEvent event) {
    reset();
  }

  /*
   * searchParameters sind vom zur Bearbeitung ausgewählten Wahltermin abhängig.
   */
  public void onWahlterminSelectChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) WahlterminSelectChangeEvent event) {
    reset();
  }

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