
package de.ivu.elect.presentation.wahl.form;

import static java.util.Arrays.asList;

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

import javax.enterprise.inject.Specializes;
import javax.inject.Inject;

import de.ivu.elect.business.CurrentCustomer;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartExtendedDAO;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsarteigenschaftExtendedDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsarteigenschaft;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.system.entity.SystemGebietsebene;
import de.ivu.elect.business.wahl.entity.AbstractWahlart;
import de.ivu.elect.business.wahl.entity.CommonWahlart;
import de.ivu.elect.business.wahl.entity.UmgangAWerte;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.business.wahl.entity.WahlartDokumentvorlagen;
import de.ivu.elect.business.wahl.entity.WahlartProperties;
import de.ivu.elect.business.wahl.entity.WahlartSitzberechnungsalgorithmus;
import de.ivu.elect.jee.presentation.dynamicform.AbstractEnumProperty;
import de.ivu.elect.jee.presentation.dynamicform.AbstractLongProperty;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaEnumProperty;
import de.ivu.elect.jee.presentation.dynamicform.ReadOnlyStringProperty;

@Specializes
public class CommonWahlartViewFormBuilder extends WahlartViewFormBuilder {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient GebietsarteigenschaftExtendedDAO gebietsarteigenschaftExtendedDAO;

  @Inject
  private transient GebietsartExtendedDAO gebietsartExtendedDAO;

  @Inject
  private transient CurrentCustomer currentCustomer;

  public CommonWahlartViewFormBuilder() {
    super();
  }

  public GebietsartPickListProperty addPropertiesMitGebietsart(FormBuilder formBuilder, Wahlart wahlart) {
    boolean wahlartNichtAnpassbar = !isWahlartAnpassbar(wahlart.getMandant());

    return addPropertiesMitGebietsart(formBuilder, wahlart, wahlartNichtAnpassbar);
  }

  private GebietsartPickListProperty addPropertiesMitGebietsart(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    super.addProperties(formBuilder, wahlart, wahlartNichtAnpassbar);

    Mandant mandant = wahlart.getMandant();
    WahlartProperties wahlartProperties = wahlart.getProperties();

    List<Gebietsart> gebietsartenZugeordnet = gebietsarteigenschaftExtendedDAO.findByAll(mandant).stream() //
        .filter(gebietsarteigenschaft -> gebietsarteigenschaft.getWahlart().equals(wahlart)) //
        .map(Gebietsarteigenschaft::getGebietsart) //
        .collect(Collectors.toList());

    GebietsartPickListProperty gebietsartProperty = new GebietsartPickListProperty(gebietsartExtendedDAO.findByAll(mandant), gebietsartenZugeordnet);
    formBuilder.addProperty(gebietsartProperty).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getSystemGebietsebeneMitLeererAuswahlProperty()).withReadonly(wahlartNichtAnpassbar);

    addDefaultCommonProperties(formBuilder, wahlart, wahlartNichtAnpassbar);

    formBuilder.addSeparator("wahlart.edit.page.dokumentvorlagen.separator");

    LambdaEnumProperty<WahlartDokumentvorlagen> dokumentvorlagenProperty = wahlartProperties.getDokumentvorlagenMitLeererAuswahlProperty();
    dokumentvorlagenProperty.setValueFilter(value -> value.isGeeignetFuer(currentCustomer.getCustomer(), /*kein Filter*/ SystemGebietsebene.OHNE));
    formBuilder.addProperty(dokumentvorlagenProperty).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getWahlbezeichnungLangProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getWahlausschussbezeichnungProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getZuWaehlendesGremiumProperty()).withReadonly(wahlartNichtAnpassbar);

    return gebietsartProperty;
  }

  private void addDefaultCommonProperties(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    WahlartProperties wahlartProperties = wahlart.getProperties();

    addAnzahlStimmenProWaehlerProperties(formBuilder, wahlart, wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getGruppenreihenfolgeVorgegebenProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getGruppenvereinigungenErlaubtProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getLeereListenErlaubtProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getListenverbindungenErlaubtProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getMaxAnzahlNennungenProperty()).withReadonly(wahlartNichtAnpassbar);

    addAnzahlErsatzkandidaturenProperty(formBuilder, wahlart, wahlartNichtAnpassbar);

    addZulassungspruefungProperties(formBuilder, wahlart, wahlartNichtAnpassbar);

    addUmgangKopfzahlenProperties(formBuilder, wahlart, wahlartNichtAnpassbar);

    formBuilder.addSeparator("wahlart.edit.page.erfassung.separator");
    formBuilder.addProperty(wahlartProperties.getErgebnisartUmschaltbarProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getErfassungUebernahmeArtProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getErfassungUebernahmeManuellProperty()).withReadonly(wahlartNichtAnpassbar);
  }

  @Override
  protected LambdaEnumProperty<CommonWahlart> addSystemWahlartProperties(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    LambdaEnumProperty<CommonWahlart> commonWahlartProperty = super.addSystemWahlartProperties(formBuilder, wahlart, wahlartNichtAnpassbar);

    LambdaEnumProperty<WahlartSitzberechnungsalgorithmus> sitzberechnungsalgorithmusProperty = wahlart.getProperties().getSitzberechnungsalgorithmusMitLeererAuswahlProperty();
    sitzberechnungsalgorithmusProperty.setValueFilter(value -> value.isGeeignetFuer(currentCustomer.getCustomer()));

    formBuilder.addProperty(sitzberechnungsalgorithmusProperty).withReadonly(wahlartNichtAnpassbar);

    if (!wahlartNichtAnpassbar) { // ELECT-8632
      sitzberechnungsalgorithmusProperty.appendObservedPropertyValueChangedConsumer(other -> {
        if (other.equals(commonWahlartProperty)) {
          CommonWahlart commonWahlart = commonWahlartProperty.getValue();

          if (commonWahlart != null) {
            sitzberechnungsalgorithmusProperty.setValue(commonWahlart.getSitzberechnungsalgorithmus());
          }
        }
      });

      formBuilder.withObservedProperty(commonWahlartProperty);
    }

    return commonWahlartProperty;
  }

  private void addZulassungspruefungProperties(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    formBuilder.addSeparator("wahlart.edit.page.zulassungspruefung.separator");
    formBuilder.addProperty(wahlart.getProperties().getZulassungspruefungProperty()).withReadonly(wahlartNichtAnpassbar);
  }

  private void addAnzahlStimmenProWaehlerProperties(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    WahlartProperties wahlartProperties = wahlart.getProperties();

    formBuilder.addProperty(wahlartProperties.getAnzahlStimmenProWaehlerArtProperty()).withReadonly(wahlartNichtAnpassbar);

    if (isAnzahlStimmenProWaehlerRelevant(wahlart, wahlartNichtAnpassbar)) {
      formBuilder.addProperty(wahlartProperties.getAnzahlStimmenProWaehlerProperty()).withReadonly(wahlartNichtAnpassbar);
    }
  }

  private boolean isAnzahlStimmenProWaehlerRelevant(Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    return !wahlartNichtAnpassbar || wahlart.isWahlMitAnzahlStimmenProWaehlerPerWahlart();
  }

  private void addAnzahlErsatzkandidaturenProperty(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    if (isAnzahlErsatzkandidaturenRelevant(wahlart, wahlartNichtAnpassbar)) {
      AbstractLongProperty maxAnzahlErsatzkandidaturenProperty = wahlart.getProperties().getMaxAnzahlErsatzkandidaturenProperty();

      if (wahlartNichtAnpassbar && wahlart.isWahlMitBeliebigVielenErsatzkandidaturen()) {
        formBuilder.addProperty(new ReadOnlyStringProperty(maxAnzahlErsatzkandidaturenProperty.getLabel(), getMessage(AbstractWahlart.BELIEBIG_VIELE_ERSATZKANIDATUREN_MSG_KEY)));
      } else {
        formBuilder.addProperty(maxAnzahlErsatzkandidaturenProperty).withReadonly(wahlartNichtAnpassbar);
      }
    }
  }

  private boolean isAnzahlErsatzkandidaturenRelevant(Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    return !wahlartNichtAnpassbar || wahlart.isWahlMitErsatzkandidaturen();
  }

  private void addUmgangKopfzahlenProperties(FormBuilder formBuilder, Wahlart wahlart, boolean wahlartNichtAnpassbar) {
    WahlartProperties wahlartProperties = wahlart.getProperties();

    formBuilder.addSeparator("wahlart.edit.page.kopfzahlen.umgang.VORLAEUFIG.separator");

    AbstractEnumProperty<UmgangAWerte> umgangAPruefkennzeichenVorlaeufigProperty = wahlartProperties.getUmgangAPruefkennzeichenVorlaeufigProperty();

    List<UmgangAWerte> umgangAWertePruefkennzeichen = new ArrayList<>(asList(UmgangAWerte.values()));
    umgangAWertePruefkennzeichen.remove(UmgangAWerte.NUR_AUSWERTEN);
    umgangAWertePruefkennzeichen.remove(UmgangAWerte.ERFASSEN_ODER_ANZEIGEN_NACH_WERTE_AM_GEBIET);

    if (isUmgangAPruefkennzeichenRelevant(wahlartNichtAnpassbar, umgangAPruefkennzeichenVorlaeufigProperty)) {
      formBuilder.addProperty(umgangAPruefkennzeichenVorlaeufigProperty).setValues(umgangAWertePruefkennzeichen);
    }

    formBuilder.addProperty(wahlartProperties.getUmgangAOhneWahlscheinVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangAMitWahlscheinVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangANichtImWaehlerverzeichnisVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangAGesamtVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getUmgangBOhneWahlscheinVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangBMitWahlscheinVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangBGesamtVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getUmgangGueltigeVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangUngueltigeVorlaeufigProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addSeparator("wahlart.edit.page.kopfzahlen.umgang.ENDGUELTIG.separator");

    AbstractEnumProperty<UmgangAWerte> umgangAPruefkennzeichenEndgueltigProperty = wahlartProperties.getUmgangAPruefkennzeichenEndgueltigProperty();

    if (isUmgangAPruefkennzeichenRelevant(wahlartNichtAnpassbar, umgangAPruefkennzeichenEndgueltigProperty)) {
      formBuilder.addProperty(umgangAPruefkennzeichenEndgueltigProperty).setValues(umgangAWertePruefkennzeichen);
    }

    formBuilder.addProperty(wahlartProperties.getUmgangAOhneWahlscheinEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangAMitWahlscheinEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangANichtImWaehlerverzeichnisEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangAGesamtEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getUmgangBOhneWahlscheinEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangBMitWahlscheinEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangBGesamtEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);

    formBuilder.addProperty(wahlartProperties.getUmgangGueltigeEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
    formBuilder.addProperty(wahlartProperties.getUmgangUngueltigeEndgueltigProperty()).withReadonly(wahlartNichtAnpassbar);
  }

  private boolean isUmgangAPruefkennzeichenRelevant(boolean wahlartNichtAnpassbar, AbstractEnumProperty<UmgangAWerte> umgangAPruefkennzeichenProperty) {
    return true; // ELECTDD-580, !wahlartNichtAnpassbar || !UmgangAWerte.NICHT_VORHANDEN.equals(umgangAPruefkennzeichenProperty.getValue());
  }
}
