
package de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Named;

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

import de.ivu.elect.business.dokumente.boundary.AbstractDokumentGenerator;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisSessionSelect;
import de.ivu.elect.business.ergebnis.boundary.GesamtErgebnisDokumentContext;
import de.ivu.elect.business.ergebnis.boundary.GesamtErgebnisDokumentGenerator;
import de.ivu.elect.business.ergebnis.control.ErgebnisExchangeContext;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.gebietsbaum.boundary.GebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartCreator;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartTemplate;
import de.ivu.elect.business.gebietsbaum.control.GebietByBreadthFirstComparator;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatterKandidaturFormatDarstellung;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.stimmeingabe.boundary.ErgebniseingangKonfiguration;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.presentation.View;
import de.ivu.elect.presentation.dokumente.AbstractDokumentErzeugenView;
import de.ivu.elect.presentation.dokumente.ElectDokumentContextGenerator;
import de.ivu.elect.presentation.ergebnis.ErgebnisStatusInfo;
import de.ivu.elect.presentation.ergebnis.ViewHavingErgebnisStatusInfo;
import de.ivu.elect.presentation.ergebnis.WasErgebnisStatusInfo;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;
import de.ivu.elect.presentation.wahlvorschlag.form.WahlvorschlagDokumentErzeugenViewFormBuilder;


import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

@OnlineHilfeId("158")
@GroupedConversationScoped
@ConversationGroup(GesamtErgebnisDokumentErzeugenView.class)
@Named(GesamtErgebnisDokumentErzeugenView.COMPONENT_NAME)
@View(viewId = GesamtErgebnisDokumentErzeugenView.VIEW_ID, useCase = UseCasePermission.DOKUMENT_ERZEUGEN_GESAMT_ERGEBNIS)
public class GesamtErgebnisDokumentErzeugenView extends AbstractDokumentErzeugenView<Ergebnis, GesamtErgebnisDokumentContext> implements ViewHavingErgebnisStatusInfo {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "gesamtErgebnisDokumentErzeugenView";

  public static final String VIEW_ID = "/ergebnis/gesamt-ergebnis-dokument-erzeugen-view.xhtml";

  @Inject
  private transient ErgebnisSessionSelect ergebnisSessionSelect;

  @Inject
  private transient ElectDokumentContextGenerator electDokumentContextGenerator;

  @Inject
  private transient GesamtErgebnisDokumentGenerator gesamtErgebnisDokumentGenerator;

  @Inject
  private transient GebietsartCreator gebietsartCreator;

  @Inject
  private transient GebietExtendedDAO gebietExtendedDAO;

  @Inject
  private transient WahlvorschlagDokumentErzeugenViewFormBuilder wahlvorschlagDokumentErzeugenViewFormBuilder;

  @Inject
  private transient ErgebniseingangKonfiguration ergebniseingangKonfiguration;

  private StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung;

  private Map<GebietsartTemplate, GebietsartAuswahlProperty> gebietsartAusWahlproperties;

  public GesamtErgebnisDokumentErzeugenView() {
    super();
  }

  @Override
  protected UseCasePermission getRequiredPermission() {
    return UseCasePermission.DOKUMENT_ERZEUGEN_GESAMT_ERGEBNIS;
  }

  @Override
  public String getViewId() {
    return VIEW_ID;
  }

  @Override
  @PreConditionCheck
  public String checkPreCondition() {
    if (isErgebnisSelected()) {
      return super.checkPreCondition();
    }

    return startViewResolver.getStartViewId();
  }

  public String getGebietName() {
    return getSelectedGebietNameFormatted();
  }

  @Override
  protected List<Ergebnis> getEntities() {
    return singletonList(getSelectedErgebnis());
  }

  @Override
  protected AbstractDokumentGenerator<Ergebnis, GesamtErgebnisDokumentContext> getDokumentGenerator() {
    return gesamtErgebnisDokumentGenerator;
  }

  @Override
  protected GesamtErgebnisDokumentContext getContext() {
    return createContext(new ErgebnisExchangeContext(getSelectedWahl(), asList(getSelectedGebiet()), getKandidaturFormatDarstellung()), getGebieteMitDetailsGebietsarten());
  }

  public GesamtErgebnisDokumentContext createContext(ErgebnisExchangeContext ergebnisExchangeContext, Collection<GebietsartTemplate> gebieteMitDetailsGebietsarten) {
    return new GesamtErgebnisDokumentContext(electDokumentContextGenerator.createElectDokumentContext(), ergebnisExchangeContext, gebieteMitDetailsGebietsarten);
  }

  @Override
  public void addDokumentParameterProperties(FormBuilder formBuilder) {
    super.addDokumentParameterProperties(formBuilder);

    wahlvorschlagDokumentErzeugenViewFormBuilder.addPropertyKandidaturFormatDarstellung(formBuilder, getSelectedWahl(), this::getKandidaturFormatDarstellung, this::setKandidaturFormatDarstellung,
        true); // ELECT-9339

    List<GebietsartTemplate> gebietsartTemplates = collectAllGebietsartTemplates();

    gebietsartAusWahlproperties = new HashMap<>();

    if (!gebietsartTemplates.isEmpty()) {
      formBuilder.addSeparator("gesamtergebnis.dokument.details.separator");

      for (GebietsartTemplate gebietsartTemplate : gebietsartTemplates) {
        GebietsartAuswahlProperty property = new GebietsartAuswahlProperty(gebietsartTemplate, getMessages());

        formBuilder.addProperty(property);

        gebietsartAusWahlproperties.put(gebietsartTemplate, property);
      }
    }
  }

  public StimmzettelFormatterKandidaturFormatDarstellung getKandidaturFormatDarstellung() {
    return kandidaturFormatDarstellung;
  }

  public void setKandidaturFormatDarstellung(StimmzettelFormatterKandidaturFormatDarstellung kandidaturFormatDarstellung) {
    this.kandidaturFormatDarstellung = kandidaturFormatDarstellung;
  }

  private Set<GebietsartTemplate> getGebieteMitDetailsGebietsarten() {
    Set<GebietsartTemplate> result = new HashSet<>();

    if (gebietsartAusWahlproperties != null) {
      for (Entry<GebietsartTemplate, GebietsartAuswahlProperty> entry : gebietsartAusWahlproperties.entrySet()) {
        if (entry.getValue().getValue()) {
          result.add(entry.getKey());
        }
      }
    }

    return result;
  }

  public List<GebietsartTemplate> collectAllGebietsartTemplates() {
    List<GebietsartTemplate> result = new ArrayList<>();

    Mandant mandant = getMandant();
    if (mandant == null) {
      return emptyList(); // NPE nach Logout
    }
    Collection<? extends GebietsartTemplate> gebietsarten = gebietsartCreator.getGebietsartTemplates(mandant);

    List<Gebiet> gebieteSortiert = new ArrayList<>(collectAllGebiete());
    Collections.sort(gebieteSortiert, new GebietByBreadthFirstComparator());

    for (Gebiet gebiet : gebieteSortiert) {
      GebietsartTemplate template = gebiet.getGebietsart().getCustomGebietsartTemplate(gebietsarten);

      if (!result.contains(template)) {
        result.add(template);
      }
    }

    return result;
  }

  private Collection< ? extends Gebiet> collectAllGebiete() {
    if (isWahlSelected()) {
      return gebietExtendedDAO.findByWahl(getSelectedWahl());
    }

    return new ArrayList<>();
  }

  @Override
  public ErgebnisStatusInfo getErgebnisStatusInfo() {
    return new WasErgebnisStatusInfo(getMessages(), getSelectedWahl(), ergebniseingangKonfiguration, getSelectedErgebnis());
  }

  private boolean isErgebnisSelected() {
    return ergebnisSessionSelect.isSelected();
  }

  private Ergebnis getSelectedErgebnis() {
    return ergebnisSessionSelect.getEntity();
  }
}
