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

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

import javax.inject.Inject;

import de.ivu.elect.business.anschrift.entity.Anschrift;
import de.ivu.elect.business.gebietsbaum.boundary.GebietExtendedDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.boundary.PolitischeGruppeExtendedDAO;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.person.control.EntityMitPersonendatenByNamenComparator;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.PersonendatenConstants;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlausschuss.boundary.WahlausschussmitgliedExtendedDAO;
import de.ivu.elect.business.wahlausschuss.entity.Wahlausschussmitglied;
import de.ivu.elect.business.wahlausschuss.entity.WahlausschussmitgliedProperties;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.Property;
import de.ivu.elect.presentation.AbstractEntitySelectOneMenuProperty;
import de.ivu.elect.presentation.anschrift.form.AnschriftViewFormBuilder;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;
import de.ivu.elect.presentation.gebietsbaum.GebietSearchProperty;
import de.ivu.elect.presentation.gruppe.form.GruppeSearchProperty;
import de.ivu.elect.presentation.person.form.CommonPersonendatenViewFormBuilder;
import de.ivu.elect.presentation.personenregister.form.AbstractPersonenregisterPropertiesViewFormBuilder;
import de.ivu.elect.presentation.security.GebietSecurity;


import static org.apache.commons.lang3.StringUtils.isBlank;

public class WahlausschussmitgliedViewFormBuilder extends AbstractPersonenregisterPropertiesViewFormBuilder {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient PolitischeGruppeExtendedDAO politischeGruppeDAO;

  @Inject
  private transient GebietExtendedDAO gebietDAO;

  @Inject
  private transient WahlausschussmitgliedExtendedDAO wahlausschussmitgliedDAO;

  @Inject
  private transient GebietNummerFormatter gebietNummerFormatter;

  @Inject
  private transient CommonPersonendatenViewFormBuilder personendatenViewFormBuilder;

  @Inject
  private transient AnschriftViewFormBuilder anschriftViewFormBuilder;

  @Inject
  private transient GebietSecurity gebietSecurity;

  public WahlausschussmitgliedViewFormBuilder() {
    super();
  }

  public void addProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied) {
    addProperties(formBuilder, wahlausschussmitglied, false);
  }

  public void addProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, boolean propertiesReadonly) {
    addProperties(formBuilder, wahlausschussmitglied, propertiesReadonly, propertiesReadonly);
  }

  public void addProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, boolean propertiesReadonly, boolean personenregisterPropertiesReadonly) {
    addWahlausschussdatenPropertiesSeparator(formBuilder, wahlausschussmitglied);
    addWahlausschussdatenProperties(formBuilder, wahlausschussmitglied, propertiesReadonly);

    formBuilder.addSeparator("wahlausschussmitglied.vertretung");

    Property vertreterProperty = new WahlausschussmitgliedSelectOneMenuProperty(getMessages(), bestimmeMoeglicheVertreter(wahlausschussmitglied), true, wahlausschussmitglied);

    formBuilder.addProperty(vertreterProperty).withReadonly(propertiesReadonly);

    formBuilder.addSeparator(PersonendatenConstants.MESSAGE_KEY_ENTITY_EINZAHL);

    addWahlausschussmitgliedPersonendatenProperties(formBuilder, wahlausschussmitglied, propertiesReadonly, personenregisterPropertiesReadonly);

    addWahlausschussmitgliedAnschriftdatenProperties(formBuilder, wahlausschussmitglied, wahlausschussmitglied.getAnschrift(), propertiesReadonly, personenregisterPropertiesReadonly);

    addWahlausschussmitgliedErreichbarkeitsdatenProperties(formBuilder, wahlausschussmitglied, propertiesReadonly);
  }

  public void addWahlausschussdatenPropertiesSeparator(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied) {
    formBuilder.addSeparator("wahlausschussmitglied.wahlausschussdaten");
  }

  public void addWahlausschussdatenProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, boolean readonly) {
    Wahl wahl = wahlausschussmitglied.getWahl();
    WahlausschussmitgliedProperties wahlausschussmitgliedProperties = wahlausschussmitglied.getProperties();

    List<Gebiet> gebiete = filterGebiete(gebietDAO.findByWahlOrderByPosition(wahl));
    formBuilder.addProperty(new GebietSearchProperty(wahlausschussmitglied, gebiete, false,
        gebietNummerFormatter)).withReadonly(readonly);

    formBuilder.addProperty(wahlausschussmitgliedProperties.getWahlausschussrolleMitLeererAuswahlProperty()).required().withReadonly(readonly);

    AbstractEntitySelectOneMenuProperty<PolitischeGruppe> politischeGruppeProperty = new GruppeSearchProperty<>(wahlausschussmitglied,
        politischeGruppeDAO.findByWahlOrderByKurzname(wahl), true);

    if (!readonly || politischeGruppeProperty.hasValue()) {
      formBuilder.addProperty(politischeGruppeProperty).withReadonly(readonly);
    }
  }

  private List<Gebiet> filterGebiete(List<Gebiet> gebiete) {
    return gebietSecurity.getBearbeitenGebietSecurity().filterGebiete(gebiete);
  }

  private List<Wahlausschussmitglied> bestimmeMoeglicheVertreter(Wahlausschussmitglied wahlausschussmitglied) {
    List<Wahlausschussmitglied> result = new ArrayList<>();

    List<Wahlausschussmitglied> moeglicheVertreter = new ArrayList<>(wahlausschussmitgliedDAO.findByWahl(wahlausschussmitglied.getWahl()));

    for (Wahlausschussmitglied moeglicherVertreter : moeglicheVertreter) {
      if (!moeglicherVertreter.equals(wahlausschussmitglied) && !moeglicherVertreter.isVertreterVorhanden()) {

        Wahlausschussmitglied zuVertetendesWahlausschussmitglied = moeglicherVertreter.getZuVertetendesWahlausschussmitglied();
        if (!moeglicherVertreter.isVertrittJemanden() || zuVertetendesWahlausschussmitglied != null && zuVertetendesWahlausschussmitglied
            .equals(wahlausschussmitglied)) {
          result.add(moeglicherVertreter);
        }
      }
    }

    Collections.sort(moeglicheVertreter, new EntityMitPersonendatenByNamenComparator<Wahlausschussmitglied>());

    return result;
  }

  protected void addWahlausschussmitgliedPersonendatenProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, boolean propertiesReadonly,
      boolean personenregisterPropertiesReadonly) {
    boolean ordnungsmerkmalPropertyAndWahlrechtsausschlussPropertyReadonly = propertiesReadonly || isPersonenregisterAbgeglichenAndNotPersonenregisterAbgleichUeberschreibbar(wahlausschussmitglied);

    WahlausschussmitgliedProperties wahlausschussmitgliedProperties = wahlausschussmitglied.getProperties();
    Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen = getPersonenregisterPropertiesUebernommen(wahlausschussmitglied);

    formBuilder.addProperty(wahlausschussmitgliedProperties.getExternesOrdnungsmerkmalProperty()).withReadonly(ordnungsmerkmalPropertyAndWahlrechtsausschlussPropertyReadonly);

    addPersonenregisterProperty(formBuilder, wahlausschussmitglied, wahlausschussmitgliedProperties.getAnredeProperty(), propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);
    addPersonenregisterProperty(formBuilder, wahlausschussmitglied, wahlausschussmitgliedProperties.getTitelProperty(), propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);

    personendatenViewFormBuilder.addBasicPersonendatenProperties(formBuilder, wahlausschussmitglied, propertiesReadonly, personenregisterPropertiesUebernommen, personenregisterPropertiesReadonly);

    if (isBlank(wahlausschussmitglied.getFamiliennameBestandteil())) {
      formBuilder.removeProperty(wahlausschussmitgliedProperties.getFamiliennameBestandteilProperty());
    }

    if (isBlank(wahlausschussmitglied.getVornamen())) {
      formBuilder.removeProperty(wahlausschussmitgliedProperties.getVornamenProperty());
    }

    personendatenViewFormBuilder.addStaatsangehoerigkeitProperties(formBuilder, wahlausschussmitglied, propertiesReadonly);

    formBuilder.addProperty(wahlausschussmitgliedProperties.getWahlrechtsausschlussProperty()).withReadonly(ordnungsmerkmalPropertyAndWahlrechtsausschlussPropertyReadonly);

    if (wahlausschussmitglied.isPersistent()) {
      formBuilder.addProperty(wahlausschussmitgliedProperties.getPersonStatusProperty()).readonly();
    }

    personendatenViewFormBuilder.addZuzugsdatenProperties(formBuilder, wahlausschussmitglied, propertiesReadonly);

    setWahlausschussmitgliedPersonendatenPropertiesRequired(formBuilder, wahlausschussmitglied);
  }

  public FormBuilder setWahlausschussmitgliedPersonendatenPropertiesRequired(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied) {
    return setPropertiesRequired(formBuilder, getWahlausschussmitgliedPersonendatenPropertiesRequired(wahlausschussmitglied));
  }

  public Set<Class< ? extends Property>> getWahlausschussmitgliedPersonendatenPropertiesRequired(Wahlausschussmitglied wahlausschussmitglied) {
    return personendatenViewFormBuilder.getBasicPersonendatenPropertiesRequired(wahlausschussmitglied);
  }

  protected void addWahlausschussmitgliedAnschriftdatenProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, Anschrift anschrift, boolean propertiesReadonly,
      boolean personenregisterPropertiesReadonly) {
    Collection<Class< ? extends Property>> personenregisterPropertiesUebernommen = getPersonenregisterPropertiesUebernommen(wahlausschussmitglied);

    anschriftViewFormBuilder.addPersonendatenAnschriftProperties(formBuilder, wahlausschussmitglied, anschrift, propertiesReadonly, personenregisterPropertiesUebernommen,
        personenregisterPropertiesReadonly);

    setWahlausschussmitgliedAnschriftPropertiesRequired(formBuilder, wahlausschussmitglied, anschrift);
  }

  public FormBuilder setWahlausschussmitgliedAnschriftPropertiesRequired(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, Anschrift anschrift) {
    return setPropertiesRequired(formBuilder, getWahlausschussmitgliedAnschriftPropertiesRequired(wahlausschussmitglied, anschrift));
  }

  public Set<Class< ? extends Property>> getWahlausschussmitgliedAnschriftPropertiesRequired(Wahlausschussmitglied wahlausschussmitglied, Anschrift anschrift) {
    return anschriftViewFormBuilder.getPersonendatenAnschriftPropertiesRequired(wahlausschussmitglied, anschrift);
  }

  protected void addWahlausschussmitgliedErreichbarkeitsdatenProperties(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied, boolean propertiesReadonly) {
    personendatenViewFormBuilder.addDefaultErreichbarkeitsdatenProperties(formBuilder, wahlausschussmitglied, propertiesReadonly);

    setWahlausschussmitgliedErreichbarkeitsdatenPropertiesRequired(formBuilder, wahlausschussmitglied);
  }

  public FormBuilder setWahlausschussmitgliedErreichbarkeitsdatenPropertiesRequired(FormBuilder formBuilder, Wahlausschussmitglied wahlausschussmitglied) {
    return setPropertiesRequired(formBuilder, getWahlausschussmitgliedErreichbarkeitsdatenPropertiesRequired(wahlausschussmitglied));
  }

  public Set<Class< ? extends Property>> getWahlausschussmitgliedErreichbarkeitsdatenPropertiesRequired(Wahlausschussmitglied wahlausschussmitglied) {
    return personendatenViewFormBuilder.getDefaultErreichbarkeitsdatenPropertiesRequired(wahlausschussmitglied);
  }

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

    // Cf. WahlausschussmitgliedPersonenregisterPersonendatenMapper.
    result.addAll(personendatenViewFormBuilder.getDefaultPersonenregisterPropertiesUebernommen(personendaten));
    result.addAll(anschriftViewFormBuilder.getDefaultPersonenregisterPropertiesUebernommen(personendaten));

    return result;
  }
}
