
package de.ivu.elect.presentation.veranstaltung;

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

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

import de.ivu.elect.business.person.entity.PersonendatenArt;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.veranstaltung.boundary.TeilnahmeChangeEvent;
import de.ivu.elect.business.veranstaltung.boundary.TeilnahmeEdit;
import de.ivu.elect.business.veranstaltung.boundary.TeilnahmeSearchParameters;
import de.ivu.elect.business.veranstaltung.boundary.VeranstaltungConversationSelect;
import de.ivu.elect.business.veranstaltung.entity.Teilnahme;
import de.ivu.elect.business.veranstaltung.entity.TeilnehmerStatus;
import de.ivu.elect.business.veranstaltung.entity.Veranstaltung;
import de.ivu.elect.business.veranstaltung.entity.VeranstaltungMeta;
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.jee.presentation.dynamicform.ReadOnlyBooleanProperty;
import de.ivu.elect.jee.presentation.dynamicform.ReadOnlyLongProperty;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.jee.presentation.search.AbstractSearchParameters;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.security.AbstractGebietSecurityFilter;
import de.ivu.elect.presentation.veranstaltung.action.TeilnahmeActionMenu;
import de.ivu.elect.presentation.veranstaltung.menu.AbstractTeilnehmerEinladenMenuItemEntry;
import de.ivu.elect.presentation.veranstaltung.table.TeilnahmeColumnBuilder;
import org.apache.deltaspike.core.api.scope.ViewAccessScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ViewAccessScoped
@OnlineHilfeId("356")
@Named(AbstractTeilnahmeSearchView.COMPONENT_NAME)
@View(viewId = AbstractTeilnahmeSearchView.VIEW_ID, useCase = UseCasePermission.TEILNAHME_SEARCH)
public class TeilnahmeSearchView extends AbstractTeilnahmeSearchView {

  private static final long serialVersionUID = 1L;
  private static final Logger LOG = LoggerFactory.getLogger(TeilnahmeSearchView.class);

  @Inject
  private VeranstaltungMeta veranstaltungMeta;

  @Inject
  private VeranstaltungConversationSelect veranstaltungSelect;

  @Inject
  private TeilnahmeEdit teilnahmeEdit;

  @Inject
  private transient Instance<AbstractTeilnehmerEinladenMenuItemEntry> teilnehmerEinladenMenuItemEntries;

  @Inject
  private TeilnahmeColumnBuilder teilnahmeColumnBuilder;

  @Inject
  private transient TeilnahmeActionMenu teilnahmeActionMenu;

  private List<PersonendatenArt> personendatenArten;

  private TeilnehmerStatus neuerStatus;

  public TeilnahmeSearchView() {
    super();
  }

  @Nullable
  @PreConditionCheck
  public String checkCondition() {
    if (isVeranstaltungSelected()) {
      return null;
    }

    return getStartViewId();
  }

  public void preRenderView() {
    addWarningUeberbelegungIfNecessary();
  }

  private void addWarningUeberbelegungIfNecessary() {
    if (getVeranstaltung().isUeberbelegt()) {
      addWarningMessage("teilnahme.search.ueberbelegt.warning.message", getVeranstaltung().getTeilnehmerAnzahl(), getVeranstaltung().getTeilnehmerAnzahlMax());
    }
  }

  @Override
  protected AbstractGebietSecurityFilter<Teilnahme> getGebietSecurityFilter() {
    return AbstractGebietSecurityFilter.createEntityMitGebietSecurityFilter(getEinsehenGebietSecurity());
  }

  private boolean isVeranstaltungSelected() {
    return veranstaltungSelect.isSelected();
  }

  private Veranstaltung getVeranstaltung() {
    return veranstaltungSelect.getEntity();
  }

  public String getVeranstaltungBezeichnung() {
    if (isVeranstaltungSelected()) {
      return getVeranstaltung().getBezeichnung();
    }

    return "";
  }

  @Override
  public TeilnahmeSearchParameters getSearchParameters() {
    TeilnahmeSearchParameters teilnahmeSearchParameters = super.getSearchParameters();
    teilnahmeSearchParameters.setVeranstaltung(getVeranstaltung());

    return teilnahmeSearchParameters;
  }

  @Override
  public void presetSearchParameters() {
    resetSearchParametersModel();
  }

  @Override
  public void addProperties(FormBuilder formBuilder) {
    String wildcardTooltip = getMessage(AbstractSearchParameters.WILDCARD_TOOLTIP_MSG_KEY);

    boolean vorgegebenerTeilnehmer = searchParameters.getPersonendaten().getId() != null;
    if (vorgegebenerTeilnehmer) {
      formBuilder.addProperty(new ReadOnlyBooleanProperty(getMessage("veranstaltung.search.teilnehmer.uebernommen"), true));
    }

    if (getVeranstaltung().getTeilnehmerAnzahlMax() != null) {
      formBuilder.addProperty(new ReadOnlyLongProperty(veranstaltungMeta.getTeilnehmerAnzahlMaxEinzahlMessage(),
          getVeranstaltung().getTeilnehmerAnzahlMax()));
    }

    formBuilder.addProperty(searchParameters.getTeilnehmerRolleProperty()).withReadonly(vorgegebenerTeilnehmer);
    formBuilder.addProperty(searchParameters.getTeilnehmerStatusProperty()).withReadonly(vorgegebenerTeilnehmer);
    formBuilder.addProperty(searchParameters.getTeilnehmerPersonendatenDiscriminatorProperty(getRelevantPersonendatenArten()))
        .withReadonly(vorgegebenerTeilnehmer);

    formBuilder.addProperty(searchParameters.getTeilnehmerFamiliennameProperty()).withTooltip(wildcardTooltip)
        .withReadonly(vorgegebenerTeilnehmer);
    formBuilder.addProperty(searchParameters.getTeilnehmerVornameProperty()).withTooltip(wildcardTooltip)
        .withReadonly(vorgegebenerTeilnehmer);
  }

  private List<PersonendatenArt> getRelevantPersonendatenArten() {
    if (personendatenArten == null) {
      personendatenArten = new ArrayList<>();

      for (AbstractTeilnehmerEinladenMenuItemEntry teilnehmerEinladenMenuItemEntry : teilnehmerEinladenMenuItemEntries) {
        personendatenArten.addAll(teilnehmerEinladenMenuItemEntry.getPersonendatenArten());
      }
    }

    return personendatenArten;
  }

  public boolean isBtnAlleTeilnahmenLoeschenRendered() {
    return hasPermission(UseCasePermission.TEILNAHME_DELETE);
  }

  public boolean isBtnAlleTeilnahmenLoeschenDisabled() {
    return isEmptySearchResultDisplayed();
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.TEILNAHME_DELETE)
  public String alleTeilnahmenLoeschen() {
    List<Teilnahme> searchResult = getSearchResult();

    teilnahmeEdit.deleteAll(searchResult);

    addInfoMessage("veranstaltung.teilnahmen.edit.action.delete.all.success", searchResult.size(), getVeranstaltungBezeichnung());

    resetSearchResult();

    return VIEW_ID;
  }

  public boolean isBtnBenachrichtigenRendered() {
    return hasPermission(UseCasePermission.VERANSTALTUNG_DOKUMENT_ERZEUGEN);
  }

  public boolean isBtnBenachrichtigenDisabled() {
    return isEmptySearchResultDisplayed();
  }

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

  public boolean isBtnStatusAendernRendered() {
    return hasPermission(UseCasePermission.TEILNAHME_EDIT);
  }

  public boolean isBtnStatusAendernDisabled() {
    return isEmptySearchResultDisplayed();
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.TEILNAHME_EDIT)
  public String statusAendern() {
    List<Teilnahme> searchResult = getSearchResult();
    LOG.info("Status {} für {} Teilnehmer setzen", neuerStatus, searchResult.size());

    teilnahmeEdit.statusAendern(searchResult, neuerStatus);

    addInfoMessage("veranstaltung.teilnahmen.edit.action.status.aendern.success", getMessage(neuerStatus), searchResult.size(), getVeranstaltungBezeichnung());

    resetSearchResult();

    return VIEW_ID;
  }

  public TeilnehmerStatus getNeuerStatus() {
    return neuerStatus;
  }

  public void setNeuerStatus(TeilnehmerStatus neuerStatus) {
    this.neuerStatus = neuerStatus;
  }

  public List<TeilnehmerStatus> getNeuerStatusValues() {
    return Arrays.asList(TeilnehmerStatus.values());
  }

  public String getNeuerStatusLabel(TeilnehmerStatus teilnehmerStatus) {
    return getMessage(teilnehmerStatus);
  }

  @Override
  public EagerLoadingCollector<Teilnahme> getEagerLoadingCollector() {
    EagerLoadingCollector<Teilnahme> eagerLoadingCollector = super.getEagerLoadingCollector();

    teilnahmeColumnBuilder.collectEagerLoadings(eagerLoadingCollector);

    return eagerLoadingCollector;
  }

  public void onTeilnahmeChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) TeilnahmeChangeEvent teilnahmeChangeEvent) {
    reloadSearchResultDuringPartialRequest();
    teilnahmeColumnBuilder.forceInit();
    teilnahmeActionMenu.resetMenuItemsPerEntity();
    addWarningUeberbelegungIfNecessary();
    reloadMessagesDuringPartialRequest();
  }
}
