
package de.ivu.elect.presentation.ergebnis.exchange;

import static de.ivu.elect.business.gebietsbaum.control.EntityMitWurzelgebietDAO.fromDao;
import static java.util.Arrays.asList;
import static java.util.Collections.sort;
import static org.apache.commons.lang3.StringUtils.isBlank;

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

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

import de.ivu.elect.business.dokumente.entity.DokumentVorlage;
import de.ivu.elect.business.dokumente.entity.DokumentVorlageArt;
import de.ivu.elect.business.dokumente.entity.DokumentVorlageConstants;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisGesamtergebnisTabellarischDocumentExporter;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisSessionSelect;
import de.ivu.elect.business.ergebnis.control.ErgebnisExchangeContext;
import de.ivu.elect.business.ergebnis.control.ErgebnisdokumentTypExportObject;
import de.ivu.elect.business.ergebnis.control.gesamtergebnis.ErgebnisGesamtergebnisTabellarischDocumentExportContext;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.exchange.control.AbstractExporter;
import de.ivu.elect.business.gebietsbaum.boundary.GebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.control.GebietByNummerComparator;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.wahl.entity.CommonWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.exception.ElectCommonException;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.dynamicform.AdvancedDynaFormModel;
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.dokumente.DokumentVorlageProperty;
import de.ivu.elect.presentation.exchange.AbstractExportSearchView;
import de.ivu.elect.presentation.hilfe.OnlineHilfeId;

@Named(ErgebnisGesamtergebnisTabellarischDocumentExportView.COMPONENT_NAME)
@View(viewId = ErgebnisGesamtergebnisTabellarischDocumentExportView.VIEW_ID, useCase = UseCasePermission.DOKUMENT_ERZEUGEN_NIEDERSCHRIFT)
@OnlineHilfeId(value = "317", mehrfachVergebenOk = true)
public class ErgebnisGesamtergebnisTabellarischDocumentExportView extends AbstractExportSearchView<ErgebnisdokumentTypExportObject, ErgebnisGesamtergebnisTabellarischDocumentExportContext> {

  private static final long serialVersionUID = 1L;

  public static final String COMPONENT_NAME = "ergebnisGesamtergebnisTabellarischDocumentExportView";

  public static final String VIEW_ID = "/ergebnis/ergebnis-gesamtergebnis-tabellarisch-document-export.xhtml";

  @Inject
  protected transient GebietExtendedDAO gebietExtendedDAO;

  @Inject
  protected transient ErgebnisSessionSelect ergebnisSessionSelect;

  @Inject
  protected transient ErgebnisGesamtergebnisTabellarischDocumentExporter exporter;

  @Inject
  protected transient ErgebnisGesamtergebnisTabellarischDocumentExportDescription exportDescription;

  @Inject
  protected transient ErgebnisGesamtergebnisTabellarischDocumentExportViewDokumentVorlagenProperties dokumentVorlagenProperties;

  private AdvancedDynaFormModel model;

  private ErgebnisDocumentExportViewGebietProperty<Gebiet> auswertungsgebietProperty;

  private ErgebnisDocumentExportViewAnzahlZeilenProSeiteProperty anzahlZeilenProSeiteProperty;

  private ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty dokumentVorlageErsteSeiteAnzahlSpaltenProperty;

  private ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty dokumentVorlageWeitereSeitenAnzahlSpaltenProperty;

  public ErgebnisGesamtergebnisTabellarischDocumentExportView() {
    super();
  }

  @Override
  @Nullable
  @PreConditionCheck
  public String checkPreCondition() {
    String outcome = super.checkPreCondition();

    if (isBlank(outcome)) {
      if (!ergebnisSessionSelect.isSelected()) {
        return getStartViewId();
      }

      return null;
    }

    return outcome;
  }

  public AdvancedDynaFormModel getModel() {
    if (model == null) {
      model = createModel();
    }

    return model;
  }

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

    model = null;

    auswertungsgebietProperty = null;

    anzahlZeilenProSeiteProperty = null;

    dokumentVorlagenProperties.reset();
    dokumentVorlageErsteSeiteAnzahlSpaltenProperty = null;
    dokumentVorlageWeitereSeitenAnzahlSpaltenProperty = null;
  }

  // Cf. KomErgebnisGesamtergebnisTabellarischDocumentExportSubView#createExportContext!!!
  protected AdvancedDynaFormModel createModel() {
    Wahl wahl = getSelectedWahl();

    FormBuilder formBuilder = new FormBuilder();

    boolean dokumentVorlagenNurGesamtergebnis = getExportDescription().isWahlartDokumentVorlagenNurGesamtergebnis(wahl);
    boolean dokumentVorlagenNurDirektstimmen = getExportDescription().isWahlartDokumentVorlagenNurDirektstimmen(wahl);
    boolean dokumentVorlagenNurListenstimmen = getExportDescription().isWahlartDokumentVorlagenNurListenstimmen(wahl);
    boolean dokumentVorlagenNurReferendumstimmen = getExportDescription().isWahlartDokumentVorlagenNurReferendumstimmen(wahl);

    DokumentVorlageArt dokumentVorlageArt = getDokumentVorlageArt();

    if (!dokumentVorlagenNurReferendumstimmen) {
      formBuilder.addProperty(getAuswertungsgebietProperty());
    }

    formBuilder.addProperty(getAnzahlZeilenProSeiteProperty());

    formBuilder.addSeparator(dokumentVorlagenNurGesamtergebnis ? DokumentVorlageConstants.MESSAGE_KEY_ENTITY_EINZAHL : DokumentVorlageConstants.MESSAGE_KEY_ENTITY_MEHRZAHL);

    // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis.odt
    formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyGesamtergebnis(wahl, dokumentVorlageArt));

    if (!dokumentVorlagenNurGesamtergebnis) { // ELECTMUC-1002
      boolean stimmenSeitenartIgnored = !getExportDescription().isWahlartDokumentVorlagenByStimmenSeitenart(wahl);
      String stimmenSeitenartIgnoredLabel = getMessage("ergebnis.gesamtergebnis.tabellarisch.exportieren.dokument.vorlage.property.label.stimmen");

      if (dokumentVorlagenNurDirektstimmen) {
        if (stimmenSeitenartIgnored) {
          // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen).odt
          formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteDirektstimmen(wahl, dokumentVorlageArt)).withLabel(stimmenSeitenartIgnoredLabel);
          formBuilder.addProperty(getDokumentVorlageErsteSeiteAnzahlSpaltenProperty());
        } else {
          // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen, Erste Seite).odt, gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen, Weitere Seiten).odt
          formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteDirektstimmen(wahl, dokumentVorlageArt));
          formBuilder.addProperty(getDokumentVorlageErsteSeiteAnzahlSpaltenProperty());
          formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyWeitereSeitenDirektstimmen(wahl, dokumentVorlageArt));
          formBuilder.addProperty(getDokumentVorlageWeitereSeitenAnzahlSpaltenProperty());
        }
      } else if (dokumentVorlagenNurListenstimmen) {
        if (stimmenSeitenartIgnored) {
          // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen).odt
          formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteListenstimmen(wahl, dokumentVorlageArt)).withLabel(stimmenSeitenartIgnoredLabel);
          formBuilder.addProperty(getDokumentVorlageErsteSeiteAnzahlSpaltenProperty());
        } else {
          // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen, Erste Seite).odt, gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen, Weitere Seiten).odt
          formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteListenstimmen(wahl, dokumentVorlageArt));
          formBuilder.addProperty(getDokumentVorlageErsteSeiteAnzahlSpaltenProperty());
          formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyWeitereSeitenListenstimmen(wahl, dokumentVorlageArt));
          formBuilder.addProperty(getDokumentVorlageWeitereSeitenAnzahlSpaltenProperty());
        }
      } else if (dokumentVorlagenNurReferendumstimmen) {
        // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis (Stimmen).odt
        formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteDirektstimmen(wahl, dokumentVorlageArt)).withLabel(stimmenSeitenartIgnoredLabel);
      } else {
        // Bspw. gesamtergebnis-v7-V7 Gesamtergebnis (Direktstimmen, Erste Seite).odt, gesamtergebnis-v7-V7 Gesamtergebnis (Direktstimmen, Weitere Seiten).odt
        //       gesamtergebnis-v7-V7 Gesamtergebnis (Listenstimmen, Erste Seite).odt, gesamtergebnis-v7-V7 Gesamtergebnis (Listenstimmen, Weitere Seiten).odt
        formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteDirektstimmen(wahl, dokumentVorlageArt));
        formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteListenstimmen(wahl, dokumentVorlageArt));
        formBuilder.addProperty(getDokumentVorlageErsteSeiteAnzahlSpaltenProperty());

        formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyWeitereSeitenDirektstimmen(wahl, dokumentVorlageArt));
        formBuilder.addProperty(dokumentVorlagenProperties.getDokumentVorlagePropertyWeitereSeitenListenstimmen(wahl, dokumentVorlageArt));
        formBuilder.addProperty(getDokumentVorlageWeitereSeitenAnzahlSpaltenProperty());
      }
    }

    return formBuilder.createModel();
  }

  private ErgebnisDocumentExportViewGebietProperty<Gebiet> getAuswertungsgebietProperty() {
    if (auswertungsgebietProperty == null) {
      List<Gebiet> auswertungsgebiete = new ArrayList<>(getAuswertungsgebietDefaultValues(getSelectedWahl()));
      sort(auswertungsgebiete, GebietByNummerComparator.ASCENDING);

      auswertungsgebietProperty = new ErgebnisDocumentExportViewGebietProperty<>(auswertungsgebiete);
    }

    return auswertungsgebietProperty;
  }

  private List<Gebiet> getAuswertungsgebietDefaultValues(Wahl wahl) {
    return getAuswertungsgebietDefaultValues(wahl, gebietExtendedDAO);
  }

  /**
   * @deprecated NOTE, dass die Verwendung der ersten Untergebietsebene MUC-spezifisch ist!!! Dort gilt Gemeinde -> Stimmkreis (LTW) | Stadtbezirk (Kommunalwahl) -> ..., so dass die Dokumente also per
   *             Stimmkreis (LTW) oder Stadtbezirk (Kommunalwahl) erzeugt wird.
   *
   * @see ErgebnisKandidaturenTabellarischDocumentExportView#getAuswertungsgebietDefaultValues
   * @see ByV2ErsteSchnellmeldungErgebnisseDocumentExportView#getAuswertungsgebietDefaultValues
   * @see ByV4ZaehllisteDocumentExportView#getAuswertungsgebietDefaultValues
   * @see ByV6ZweiteSchnellmeldungDocumentExportView#getAuswertungsgebietDefaultValues
   */
  @Deprecated
  public static List<Gebiet> getAuswertungsgebietDefaultValues(Wahl wahl, GebietExtendedDAO gebietExtendedDAO) {
    List<Gebiet> result = new ArrayList<>();

    Gebiet wurzelgebiet = wahl.getWurzelgebiet(fromDao(gebietExtendedDAO));

    if (wurzelgebiet != null) {
      if (CommonWahlart.BUERGERENTSCHEID.equalsWahlart(wahl)) {
        result.add(wurzelgebiet);
      } else {
        result.addAll(gebietExtendedDAO.findByUebergeordnetesGebiet(wurzelgebiet));
      }
    }

    return result;
  }

  private ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty getDokumentVorlageErsteSeiteAnzahlSpaltenProperty() {
    if (dokumentVorlageErsteSeiteAnzahlSpaltenProperty == null) {
      dokumentVorlageErsteSeiteAnzahlSpaltenProperty = new ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty(
          ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty.LABEL_MSG_KEY_ANZAHL_SPALTEN_ERSTE_SEITE, getDokumentVorlageErsteSeiteAnzahlSpaltenDefaultValue(getSelectedWahl()));
    }

    return dokumentVorlageErsteSeiteAnzahlSpaltenProperty;
  }

  public int getDokumentVorlageErsteSeiteAnzahlSpaltenDefaultValue(Wahl wahl) {
    return getExportDescription().getWahlartDokumentVorlagenErsteSeiteAnzahlSpaltenDefaultValue(wahl);
  }

  private ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty getDokumentVorlageWeitereSeitenAnzahlSpaltenProperty() {
    if (dokumentVorlageWeitereSeitenAnzahlSpaltenProperty == null) {
      dokumentVorlageWeitereSeitenAnzahlSpaltenProperty = new ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty(
          ErgebnisDocumentExportViewDokumentVorlageAnzahlSpaltenProperty.LABEL_MSG_KEY_ANZAHL_SPALTEN_WEITERE_SEITEN, getDokumentVorlageWeitereSeitenAnzahlSpaltenDefaultValue(getSelectedWahl()));
    }

    return dokumentVorlageWeitereSeitenAnzahlSpaltenProperty;
  }

  public int getDokumentVorlageWeitereSeitenAnzahlSpaltenDefaultValue(Wahl wahl) {
    return getExportDescription().getWahlartDokumentVorlagenWeitereSeitenAnzahlSpaltenDefaultValue(wahl);
  }

  private ErgebnisDocumentExportViewAnzahlZeilenProSeiteProperty getAnzahlZeilenProSeiteProperty() {
    if (anzahlZeilenProSeiteProperty == null) {
      anzahlZeilenProSeiteProperty = new ErgebnisDocumentExportViewAnzahlZeilenProSeiteProperty(getAnzahlZeilenProSeiteDefaultValue(getSelectedWahl()));
    }

    return anzahlZeilenProSeiteProperty;
  }

  public int getAnzahlZeilenProSeiteDefaultValue(Wahl wahl) {
    return getExportDescription().getWahlartDokumentVorlagenAnzahlZeilenProSeiteDefaultValue(wahl);
  }

  @Override
  protected AbstractExporter<ErgebnisdokumentTypExportObject, ErgebnisGesamtergebnisTabellarischDocumentExportContext> getExporter() {
    return exporter;
  }

  @Override
  protected ErgebnisGesamtergebnisTabellarischDocumentExportContext getContext() {
    DokumentVorlage dokumentVorlageGesamtergebnis = null;
    DokumentVorlage dokumentVorlageErsteSeiteDirektstimmen = null;
    DokumentVorlage dokumentVorlageWeitereSeitenDirektstimmen = null;
    DokumentVorlage dokumentVorlageErsteSeiteListenstimmen = null;
    DokumentVorlage dokumentVorlageWeitereSeitenListenstimmen = null;

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

      dokumentVorlageGesamtergebnis = valueOrNull(dokumentVorlagenProperties.getDokumentVorlagePropertyGesamtergebnis(wahl, getDokumentVorlageArt()));
      dokumentVorlageErsteSeiteDirektstimmen = valueOrNull(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteDirektstimmen(wahl, getDokumentVorlageArt()));
      dokumentVorlageWeitereSeitenDirektstimmen = valueOrNull(dokumentVorlagenProperties.getDokumentVorlagePropertyWeitereSeitenDirektstimmen(wahl, getDokumentVorlageArt()));
      dokumentVorlageErsteSeiteListenstimmen = valueOrNull(dokumentVorlagenProperties.getDokumentVorlagePropertyErsteSeiteListenstimmen(wahl, getDokumentVorlageArt()));
      dokumentVorlageWeitereSeitenListenstimmen = valueOrNull(dokumentVorlagenProperties.getDokumentVorlagePropertyWeitereSeitenListenstimmen(wahl, getDokumentVorlageArt()));
    }

    Integer anzahlZeilenProSeite = getAnzahlZeilenProSeiteProperty().getValue();

    Integer dokumentVorlageErsteSeiteAnzahlSpalten = getDokumentVorlageErsteSeiteAnzahlSpaltenProperty().getValue();
    Integer dokumentVorlageWeitereSeitenAnzahlSpalten = getDokumentVorlageWeitereSeitenAnzahlSpaltenProperty().getValue();

    boolean documentsCreatedPerStimmzettelgebiet = true;
    boolean documentsCreatedPerGemeinde = false;

    boolean tabellenCreatedPerDatenArt = true;

    boolean tabellenCreatedGemeindenGesamt = true;

    return createContext(new ErgebnisExchangeContext(getSelectedWahl(), getSelectedAuswertungsgebiete(), ErgebnisExchangeContext.KANDIDATUR_FORMAT_DARSTELLUNG_NOT_CONFIGURED),
        ergebnisSessionSelect.getEntity(), documentsCreatedPerStimmzettelgebiet, documentsCreatedPerGemeinde, tabellenCreatedPerDatenArt, tabellenCreatedGemeindenGesamt, anzahlZeilenProSeite,
        dokumentVorlageGesamtergebnis, dokumentVorlageErsteSeiteDirektstimmen, dokumentVorlageErsteSeiteListenstimmen, dokumentVorlageErsteSeiteAnzahlSpalten,
        dokumentVorlageWeitereSeitenDirektstimmen, dokumentVorlageWeitereSeitenListenstimmen, dokumentVorlageWeitereSeitenAnzahlSpalten);
  }

  public ErgebnisGesamtergebnisTabellarischDocumentExportContext createContext(ErgebnisExchangeContext ergebnisExchangeContext, Ergebnis ergebnis, Boolean documentsCreatedPerStimmzettelgebiet,
      Boolean documentsCreatedPerGemeinde, Boolean tabellenCreatedPerDatenArt, Boolean tabellenCreatedGemeindenGesamt, Integer anzahlZeilenProSeite, DokumentVorlage dokumentVorlageGesamtergebnis,
      DokumentVorlage dokumentVorlageErsteSeiteDirektstimmen, DokumentVorlage dokumentVorlageErsteSeiteListenstimmen, Integer dokumentVorlageErsteSeiteAnzahlSpalten,
      DokumentVorlage dokumentVorlageWeitereSeitenDirektstimmen, DokumentVorlage dokumentVorlageWeitereSeitenListenstimmen, Integer dokumentVorlageWeitereSeitenAnzahlSpalten) {
    boolean tabellenCreatedKreiseGesamt = CommonWahlart.BUNDESTAGSWAHL.equalsWahlart(getSelectedWahl()); // ELECTKOM-1697

    return new ErgebnisGesamtergebnisTabellarischDocumentExportContext(ergebnisExchangeContext, ergebnis, getBenutzer(), getMessages(), documentsCreatedPerStimmzettelgebiet,
        documentsCreatedPerGemeinde, tabellenCreatedPerDatenArt, tabellenCreatedKreiseGesamt, tabellenCreatedGemeindenGesamt, anzahlZeilenProSeite, dokumentVorlageGesamtergebnis,
        dokumentVorlageErsteSeiteDirektstimmen, dokumentVorlageErsteSeiteListenstimmen, dokumentVorlageErsteSeiteAnzahlSpalten, dokumentVorlageWeitereSeitenDirektstimmen,
        dokumentVorlageWeitereSeitenListenstimmen, dokumentVorlageWeitereSeitenAnzahlSpalten);
  }

  private List<Gebiet> getSelectedAuswertungsgebiete() {
    Gebiet auswertungsgebiet = getAuswertungsgebietProperty().getValue();

    if (auswertungsgebiet == null) {
      return getAuswertungsgebietDefaultValues(getSelectedWahl());
    }

    return asList(auswertungsgebiet);
  }

  @Nullable
  private DokumentVorlage valueOrNull(DokumentVorlageProperty property) {
    if (property == null) {
      return null;
    }

    return property.getValue();
  }

  @Override
  @Redirect
  public String exportieren() {
    ErgebnisGesamtergebnisTabellarischDocumentExportContext context = getContext();

    if (context.getDokumentVorlageGesamtergebnis() == null) {
      throw new ElectCommonException(ElectCommonException.RedirectDestination.NONE, ElectCommonException.LogLevel.MESSAGE_ONLY,
          "ergebnis.gesamtergebnis.tabellarisch.exportieren.keine.dokument.vorlage.gesamtergebnis.exception");
    }

    return super.exportieren();
  }

  public DokumentVorlageArt getDokumentVorlageArt() {
    return getExportDescription().getDokumentVorlageArt();
  }

  @Override
  public ErgebnisGesamtergebnisTabellarischDocumentExportDescription getExportDescription() {
    return exportDescription;
  }
}
