
package de.ivu.elect.presentation.niederschrift;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
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.entity.Gebiet;
import de.ivu.elect.business.niederschrift.boundary.NiederschriftExtendedDAO;
import de.ivu.elect.business.niederschrift.boundary.NiederschriftFormatter;
import de.ivu.elect.business.niederschrift.boundary.NiederschriftStatusAenderungItemConversationStore;
import de.ivu.elect.business.niederschrift.boundary.NiederschriftStatusAenderungListConversationStore;
import de.ivu.elect.business.niederschrift.entity.Niederschrift;
import de.ivu.elect.business.niederschrift.entity.NiederschriftByGebietNummerAndNiederschriftArtComparator;
import de.ivu.elect.business.niederschrift.entity.NiederschriftStatusAenderung;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.UseCaseSecure;
import de.ivu.elect.business.wahl.boundary.WahlSelectChangeEvent;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.niederschrift.form.NiederschriftStatusAenderungNiederschriftAutocompletionProperty;
import de.ivu.elect.presentation.niederschrift.form.NiederschriftStatusAenderungViewFormBuilder;

@OnlineHilfeId("331")
@Named(NiederschriftStatusAenderungCreateView.COMPONENT_NAME)
@View(viewId = NiederschriftStatusAenderungCreateView.VIEW_ID, useCase = UseCasePermission.NIEDERSCHRIFT_STATUS_AENDERUNG_CREATE)
public class NiederschriftStatusAenderungCreateView extends AbstractNiederschriftStatusAenderungCreateView {

  private static final long serialVersionUID = 1L;

  @Inject
  protected transient NiederschriftExtendedDAO niederschriftExtendedDAO;

  @Inject // NOTE, dass es hier um NICHT PERSISTIERTE Entitäten geht die keinen PK haben -- die autogenerierten ConversationStores funktionieren deshalb nicht!
  @ConversationGroup(NiederschriftStatusAenderungItemConversationStore.class)
  protected transient NiederschriftStatusAenderungItemConversationStore niederschriftStatusAenderungSelection;

  @Inject // Cf. NiederschriftStatusAenderungCreateColumnBuilder!
  @ConversationGroup(NiederschriftStatusAenderungListConversationStore.class)
  protected transient NiederschriftStatusAenderungListConversationStore niederschriftStatusAenderungenErfasst;

  @Inject
  protected transient NiederschriftStatusAenderungViewFormBuilder niederschriftStatusAenderungViewFormBuilder;

  public NiederschriftStatusAenderungCreateView() {
    super();
  }

  @Override
  protected String getParentViewId() {
    return NiederschriftSearchView.VIEW_ID;
  }

  @PreConditionCheck
  public String checkPreCondition() {
    return null; // ELECTMUC-2749
  }

  @Override
  @PostConstruct
  public void init() {
    super.init();

    if (isAnyNiederschriftStatusAenderungErfasst()) {
      // HINT: bei jedem init() die Attribute vom zuletzt erfassten Entity übernehmen, weil der View @RequestScoped ist und sonst alles vergessen würde ...
      NiederschriftStatusAenderung niederschriftStatusAenderungErfasst = getNiederschriftStatusAenderungenErfasst().get(getNiederschriftStatusAenderungenErfasst().size() - 1);

      NiederschriftStatusAenderung niederschriftStatusAenderung = getEntity();
      niederschriftStatusAenderung.setStatus(niederschriftStatusAenderungErfasst.getStatus());
      niederschriftStatusAenderung.setRaum(niederschriftStatusAenderungErfasst.getRaum());
      niederschriftStatusAenderung.setBesitzer(niederschriftStatusAenderungErfasst.getBesitzer());
    }
  }

  public NiederschriftStatusAenderung getNiederschriftStatusAenderungSelection() {
    return niederschriftStatusAenderungSelection.getEntity();
  }

  public void setNiederschriftStatusAenderungSelection(NiederschriftStatusAenderung niederschriftStatusAenderung) {
    if (niederschriftStatusAenderung != null) {
      niederschriftStatusAenderungSelection.setEntity(niederschriftStatusAenderung);
    }
  }

  private boolean isAnyNiederschriftStatusAenderungErfasst() {
    return !getNiederschriftStatusAenderungenErfasst().isEmpty();
  }

  public List<NiederschriftStatusAenderung> getNiederschriftStatusAenderungenErfasst() {
    return niederschriftStatusAenderungenErfasst.get();
  }

  private void addNiederschriftStatusAenderungenErfasst(NiederschriftStatusAenderung niederschriftStatusAenderung) {
    niederschriftStatusAenderungenErfasst.add(niederschriftStatusAenderung);
  }

  @Override
  public void addProperties(FormBuilder formBuilder, NiederschriftStatusAenderung niederschriftStatusAenderung) {
    niederschriftStatusAenderungViewFormBuilder.addProperties(formBuilder, niederschriftStatusAenderung, isAnyNiederschriftStatusAenderungErfasst());

    boolean niederschriftPropertyFocussed = isAnyNiederschriftStatusAenderungErfasst(); // HINT focused: für Direkteingabe mit Barcodescanner
    List<Niederschrift> niederschriftenInWahl = new ArrayList<>();

    Wahl wahl = getSelectedWahl();

    if (wahl != null) {
      niederschriftenInWahl.addAll(collectNiederschriftenInWahl(wahl));
    }

    // NOTE Primefaces-Bug mit "null"-Text nach Validation, cf. https://code.google.com/p/primefaces/issues/detail?id=4735
    formBuilder
        .addProperty(new NiederschriftStatusAenderungNiederschriftAutocompletionProperty(niederschriftStatusAenderung, niederschriftExtendedDAO, getNiederschriftFormatter(), niederschriftenInWahl))
        .withFocus(niederschriftPropertyFocussed);
  }

  private List<Niederschrift> collectNiederschriftenInWahl(Wahl wahl) {
    List<Niederschrift> result = new ArrayList<>();

    for (Niederschrift niederschrift : niederschriftExtendedDAO.findByWahl(wahl)) {
      Gebiet gebiet = niederschrift.getGebiet();

      if (gebiet != null && getBearbeitenGebietSecurity().isRechtVorhanden(gebiet)) {
        result.add(niederschrift);
      }
    }

    result.sort(new NiederschriftByGebietNummerAndNiederschriftArtComparator(getMessages()));

    return result;
  }

  public boolean isBtnStoreEntityInQueueRendered() {
    return true;
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.NIEDERSCHRIFT_STATUS_AENDERUNG_CREATE)
  public void storeEntityInQueue() {
    NiederschriftStatusAenderung niederschriftStatusAenderung = getEntity();
    Niederschrift niederschrift = niederschriftStatusAenderung.getNiederschrift();

    if (niederschrift != null) {
      Collection<Niederschrift> niederschriftStatusAenderungenErfasstNiederschriften = getNiederschriftStatusAenderungenErfasst().stream() //
          .map(NiederschriftStatusAenderung::getNiederschrift) //
          .collect(Collectors.toList());

      if (niederschriftStatusAenderungenErfasstNiederschriften.contains(niederschrift)) {
        addWarningMessage("niederschrift.status.aenderung.create.duplikat.message", getNiederschriftFormatter().formatAnzeigeNiederschrift(niederschrift, getMessages()),
            getNiederschriftFormatter().formatAnzeigeGebiet(niederschrift));
      } else {
        niederschriftStatusAenderung.setZeitstempel(new Date());

        addNiederschriftStatusAenderungenErfasst(niederschriftStatusAenderung);
      }

      init();

      resetModel();
    }
  }

  @Override
  public boolean isBtnSaveRendered() {
    return false; // HINT: Abgelöst durch btnSaveImmediate, um den btnStoreEntityInQueue nach vorne zu bringen
  }

  public boolean isBtnSaveImmediateRendered() {
    return !isAnyNiederschriftStatusAenderungErfasst(); // HINT: Speichern einzelner Entitäten nur zulassen, wenn nicht schon mehrere Entitäten zum Speichern vorgemerkt sind
  }

  @Override
  @Redirect
  @UseCaseSecure(UseCasePermission.NIEDERSCHRIFT_STATUS_AENDERUNG_CREATE)
  public String save() {
    getEntity().setZeitstempel(new Date());

    super.save();

    resetNiederschriftStatusAenderungenErfasst();

    return getParentViewId();
  }

  public boolean isCtnSaveAllRendered() {
    return isAnyNiederschriftStatusAenderungErfasst(); // HINT: Panel mit zwischengespeicherten Entitäten nur anzeigen, wenn solche Entitäten vorhanden sind
  }

  public boolean isBtnSaveAllRendered() {
    return true;
  }

  @Redirect
  @UseCaseSecure(UseCasePermission.NIEDERSCHRIFT_STATUS_AENDERUNG_CREATE)
  public String saveAll() {
    Collection<NiederschriftStatusAenderung> niederschriftStatusAenderungen = getNiederschriftStatusAenderungenErfasst();

    for (NiederschriftStatusAenderung niederschriftStatusAenderung : niederschriftStatusAenderungen) {
      create.save(niederschriftStatusAenderung);
    }

    long niederschriftStatusAenderungenCount = niederschriftStatusAenderungen.size();

    addInfoMessage("entity.create.action.save.success.message",
        niederschriftStatusAenderungenCount == 1 ? entityMeta.getEinzahlMessage() : getUserLocale().formatNumber(niederschriftStatusAenderungenCount) + " " + entityMeta.getMehrzahlMessage());

    return cancel();
  }

  @Override
  @Redirect
  public String reset() {
    resetNiederschriftStatusAenderungenErfasst();

    resetModel();

    NiederschriftStatusAenderung niederschriftStatusAenderung = getEntity();
    niederschriftStatusAenderung.setRaum(null);
    niederschriftStatusAenderung.setBesitzer(null);
    niederschriftStatusAenderung.setStatus(null);

    return getViewId();
  }

  @Override
  @Redirect
  public String cancel() {
    resetNiederschriftStatusAenderungenErfasst();

    return super.cancel();
  }

  private void resetNiederschriftStatusAenderungenErfasst() {
    niederschriftStatusAenderungenErfasst.reset();
    niederschriftStatusAenderungenErfasst.close();
  }

  private NiederschriftFormatter getNiederschriftFormatter() {
    return niederschriftStatusAenderungViewFormBuilder.getNiederschriftFormatter();
  }

  public void onWahlSelectChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) WahlSelectChangeEvent event) {
    reset();
  }
}
