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

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

import javax.annotation.Nullable;

import de.ivu.elect.business.anschrift.entity.Anschrift;
import de.ivu.elect.business.anschrift.entity.AnschriftArt;
import de.ivu.elect.business.anschrift.entity.AnschriftProperties;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.Property;
import de.ivu.elect.presentation.personenregister.form.AbstractPersonenregisterPropertiesViewFormBuilder;

public class AnschriftViewFormBuilder extends AbstractPersonenregisterPropertiesViewFormBuilder {

  private static final long serialVersionUID = 1L;

  public static final String LOKALITAET_MESSAGE_KEY_ORT_EINZAHL = "entity.einzahl.LOKALITAET.ANSCHRIFT.ORT";

  private static final Collection<AnschriftArt> ANSCHRIFT_ARTEN_MANUELL_ZU_ERFASSEN = asList(AnschriftArt.UNBEKANNT, AnschriftArt.ERREICHBARKEITSANSCHRIFT);

  public AnschriftViewFormBuilder() {
    super();
  }

  public void addPersonendatenAnschriftProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift) {
    addPersonendatenAnschriftProperties(formBuilder, personendaten, anschrift, false);
  }

  public void addPersonendatenAnschriftProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift, boolean propertiesReadonly) {
    addPersonendatenAnschriftProperties(formBuilder, personendaten, anschrift, propertiesReadonly, new ArrayList<>(), propertiesReadonly);
  }

  public void addPersonendatenAnschriftProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift, boolean propertiesReadonly,
      Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen, boolean personenregisterPropertiesReadonly) {
    addPersonendatenAnschriftProperties(formBuilder, personendaten, anschrift, false, propertiesReadonly, personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);
  }

  public void addPersonendatenAnschriftProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift, boolean propertiesErweitertInitialVisibleOnPageLoad,
      boolean propertiesReadonly, Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen, boolean personenregisterPropertiesReadonly) {
    AnschriftProperties anschriftProperties = anschrift.getProperties();

    addPersonenregisterProperty(formBuilder, personendaten, anschriftProperties.getAnschriftArtProperty(), propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly,
        personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);

    addBasicAnschriftProperties(formBuilder, personendaten, anschrift, propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);

    Property hausnummerzusatzProperty = anschriftProperties.getHausnummerzusatzProperty();

    addPersonenregisterProperty(formBuilder, personendaten, anschriftProperties.getWohnungsnummerProperty(), propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly,
        personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);

    if (formBuilder.containsProperty(hausnummerzusatzProperty)) { // ELECT-16373
      formBuilder.after(hausnummerzusatzProperty);
    }

    setPersonendatenAnschriftPropertiesRequired(formBuilder, personendaten, anschrift);
  }

  public void setPersonendatenAnschriftPropertiesRequired(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift) {
    setPropertiesRequired(formBuilder, getPersonendatenAnschriftPropertiesRequired(personendaten, anschrift));
  }

  public Set<Class< ? extends Property>> getPersonendatenAnschriftPropertiesRequired(@Nullable Personendaten personendaten, Anschrift anschrift) {
    return emptySet();
  }

  public void addLokalitaetAnschriftProperties(FormBuilder formBuilder, Anschrift anschrift) {
    addLokalitaetAnschriftProperties(formBuilder, anschrift, false);
  }

  public void addLokalitaetAnschriftProperties(FormBuilder formBuilder, Anschrift anschrift, boolean propertiesReadonly) {
    addBasicAnschriftProperties(formBuilder, null, anschrift, false, propertiesReadonly, new ArrayList<>(), propertiesReadonly);

    Property ortProperty = anschrift.getProperties().getOrtProperty();

    if (formBuilder.containsProperty(ortProperty)) {
      formBuilder.selectProperty(ortProperty).withLabel(getMessage(LOKALITAET_MESSAGE_KEY_ORT_EINZAHL));
    }

    setLokalitaetAnschriftPropertiesRequired(formBuilder, anschrift);
  }

  public void setLokalitaetAnschriftPropertiesRequired(FormBuilder formBuilder, Anschrift anschrift) {
    setPropertiesRequired(formBuilder, getLokalitaetAnschriftPropertiesRequired(anschrift));
  }

  public Set<Class< ? extends Property>> getLokalitaetAnschriftPropertiesRequired(Anschrift anschrift) {
    return emptySet();
  }

  protected void addBasicAnschriftProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift, boolean propertiesErweitertInitialVisibleOnPageLoad,
      boolean propertiesReadonly, Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen, boolean personenregisterPropertiesReadonly) {
    AnschriftProperties anschriftProperties = anschrift.getProperties();

    addPersonenregisterProperty(formBuilder, personendaten, anschriftProperties.getStrasseProperty(), propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly,
        personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);
    addPersonenregisterProperty(formBuilder, personendaten, anschriftProperties.getHausnummerProperty(), propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly,
        personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);
    addPersonenregisterProperty(formBuilder, personendaten, anschriftProperties.getHausnummerzusatzProperty(), propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly,
        personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);

    addPersonenregisterProperty(formBuilder, personendaten, anschriftProperties.getZustellanweisungProperty(), propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly,
        personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);

    addPlzOrtProperties(formBuilder, personendaten, anschrift, propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);
  }

  protected void addPlzOrtProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift, boolean propertiesErweitertInitialVisibleOnPageLoad,
      boolean propertiesReadonly, Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen, boolean personenregisterPropertiesReadonly) {
    AnschriftProperties anschriftProperties = anschrift.getProperties();

    addPlzOrtProperties(formBuilder, personendaten, anschrift, anschriftProperties.getPlzProperty(), anschriftProperties.getOrtProperty(), anschriftProperties.getOrtsteilProperty(),
        propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly, personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);
  }

  protected void addPlzOrtProperties(FormBuilder formBuilder, @Nullable Personendaten personendaten, Anschrift anschrift, Property plzProperty, Property ortProperty, Property ortsteilProperty,
      boolean propertiesErweitertInitialVisibleOnPageLoad, boolean propertiesReadonly, Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen,
      boolean personenregisterPropertiesReadonly) {
    addPersonenregisterProperty(formBuilder, personendaten, plzProperty, propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);
    addPersonenregisterProperty(formBuilder, personendaten, ortProperty, propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);
    addPersonenregisterProperty(formBuilder, personendaten, ortsteilProperty, propertiesErweitertInitialVisibleOnPageLoad, propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);
  }

  @Override
  protected boolean isPersonenregisterPropertyReadonlySupported(@Nullable Personendaten personendaten, boolean personenregisterPropertyReadonly) {
    if (super.isPersonenregisterPropertyReadonlySupported(personendaten, personenregisterPropertyReadonly)) {
      return personendaten != null && !ANSCHRIFT_ARTEN_MANUELL_ZU_ERFASSEN.contains(personendaten.getAnschrift().getAnschriftArt());
    }

    return false;
  }

  @Override
  public Collection<Class< ? extends Property>> getPersonenregisterPropertiesUebernommen(@Nullable Personendaten personendaten) {
    // NOTE, dass keine allgemeine Implementierung für existiert, da die übernommenen Felder von der jeweiligen Entität,
    // bspw. Wahlhelfer, Wahlausschussmitglied, etc., abhängen!
    return emptyList();
  }

  public Collection<Class< ? extends Property>> getDefaultPersonenregisterPropertiesUebernommen(@Nullable Personendaten personendaten) {
    Collection<Class< ? extends Property>> result = new ArrayList<>();

    // Cf. PersonendatenAnschriftPersonenregisterAnschriftMapper.
    result.add(AnschriftProperties.AnschriftArtProperty.class);
    result.add(AnschriftProperties.AnschriftArtMitLeererAuswahlProperty.class);

    result.add(AnschriftProperties.StrasseProperty.class);
    result.add(AnschriftProperties.HausnummerProperty.class);
    result.add(AnschriftProperties.HausnummerzusatzProperty.class);
    result.add(AnschriftProperties.WohnungsnummerProperty.class);

    result.add(AnschriftProperties.PlzProperty.class);
    result.add(AnschriftProperties.OrtProperty.class);
    result.add(AnschriftProperties.OrtsteilProperty.class);

    result.add(AnschriftProperties.ZustellanweisungProperty.class);

    return result;
  }
}
