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

import static java.util.Collections.emptyList;
import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.util.Collection;

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

import de.ivu.elect.business.anschrift.boundary.AnschriftFactory;
import de.ivu.elect.business.anschrift.entity.Anschrift;
import de.ivu.elect.business.person.control.GeschlechtFilter;
import de.ivu.elect.business.person.entity.Geschlecht;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.PersonendatenProperties;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktMeta;
import de.ivu.elect.jee.faces.FacesContextUtil;
import de.ivu.elect.jee.presentation.dynamicform.AbstractEnumProperty;
import de.ivu.elect.jee.presentation.dynamicform.AbstractProperty;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.Property;
import de.ivu.elect.jee.presentation.dynamicform.ReadOnlyLongProperty;
import de.ivu.elect.presentation.ViewFormBuilder;
import de.ivu.elect.presentation.anschrift.form.AnschriftViewFormBuilder;
import de.ivu.elect.presentation.person.form.PersonendatenPersonendatenTagAutoCompleteOptionsProvider;
import de.ivu.elect.presentation.person.form.PersonendatenPersonendatenTagAutoCompleteProperty;

public class PersonenKonfliktDublettenAufloesenViewFormBuilder extends ViewFormBuilder {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient AnschriftFactory anschriftFactory;

  @Inject
  private transient PersonenKonfliktMeta personenKonfliktMeta;

  @Inject
  private transient AnschriftViewFormBuilder anschriftViewFormBuilder;

  @Inject
  private transient GeschlechtFilter geschlechtFilter;

  @Inject
  private transient PersonendatenPersonendatenTagAutoCompleteOptionsProvider personendatenPersonendatenTagAutoCompleteOptionsProvider;

  public PersonenKonfliktDublettenAufloesenViewFormBuilder() {
    super();
  }

  public String getPersonendatenHeader(Personendaten personendaten) {
    return personenKonfliktMeta.getPersonendatenEinzahlMessage();
  }

  public void addProperties(FormBuilder formBuilder, Personendaten one, @Nullable Personendaten another) {
    boolean verificationEnabled = another != null;

    addVerifiedPersonendatenProperties(formBuilder, verificationEnabled, one, another);
    addVerifiedAnschriftProperties(formBuilder, verificationEnabled, one.getAnschrift(), fixNullToEmptyAnschrift(another));

    formBuilder.globalReadonly();
  }

  protected void addVerifiedPersonendatenProperties(FormBuilder formBuilder, boolean verificationEnabled, Personendaten one, @Nullable Personendaten another) {
    PersonendatenProperties properties = one.getProperties();

    Long id = one.getId(); // ID zur Fehleranalyse...

    if (FacesContextUtil.isDevelopmentStage()) {
      formBuilder.addProperty(new ReadOnlyLongProperty("PK", id));
    }

    Property ordnungsmerkmalProperty = properties.getExternesOrdnungsmerkmalProperty();

    formBuilder.addProperty(ordnungsmerkmalProperty);
    if (verificationEnabled && another != null && isDublettenrelevant(ordnungsmerkmalProperty)) {
      tryAddVerificationMessage(formBuilder, one.getOrdnungsmerkmal(), another.getOrdnungsmerkmal());
    }

    formBuilder.addProperty(properties.getAnredeProperty());
    formBuilder.addProperty(properties.getTitelProperty());

    Property familiennameProperty = properties.getFamiliennameProperty();

    formBuilder.addProperty(familiennameProperty).withTooltip("" + id);
    if (verificationEnabled && another != null && isDublettenrelevant(familiennameProperty)) {
      tryAddVerificationMessage(formBuilder, one.getFamilienname(), another.getFamilienname());
    }

    Property rufnameProperty = properties.getRufnameProperty();

    formBuilder.addProperty(rufnameProperty);
    if (verificationEnabled && another != null && isDublettenrelevant(rufnameProperty)) {
      tryAddVerificationMessage(formBuilder, one.getRufname(), another.getRufname());
    }

    Property vornamenProperty = properties.getVornamenProperty();

    formBuilder.addProperty(vornamenProperty);
    if (verificationEnabled && another != null && isDublettenrelevant(vornamenProperty)) {
      tryAddVerificationMessage(formBuilder, one.getVornamen(), another.getVornamen());
    }

    AbstractEnumProperty<Geschlecht> geschlechtProperty = properties.getGeschlechtProperty();
    geschlechtProperty.setValueFilter(geschlechtFilter);

    formBuilder.addProperty(geschlechtProperty);
    if (verificationEnabled && another != null && isDublettenrelevant(geschlechtProperty)) {
      tryAddVerificationMessage(formBuilder, one.getGeschlecht(), another.getGeschlecht());
    }

    Property geburtsdatumProperty = properties.getGeburtsdatumProperty();

    formBuilder.addProperty(geburtsdatumProperty);
    if (verificationEnabled && another != null && isDublettenrelevant(geburtsdatumProperty)) {
      tryAddVerificationMessage(formBuilder, one.getGeburtsdatum(), another.getGeburtsdatum());
    }

    formBuilder.addProperty(properties.getGeburtsortProperty());

    formBuilder.addProperty(properties.getPersonStatusProperty());

    if (!one.getPersonendatenTag().isEmpty() || another != null && !another.getPersonendatenTag().isEmpty()) { // ELECT-10853
      formBuilder.addProperty(new PersonendatenPersonendatenTagAutoCompleteProperty(one, personendatenPersonendatenTagAutoCompleteOptionsProvider, false));
    }
  }

  protected void addVerifiedAnschriftProperties(FormBuilder formBuilder, boolean verificationEnabled, Anschrift one, Anschrift another) {
    // NOTE, dass zur Anschrift keine Hinweise angezeigt werden.
    anschriftViewFormBuilder.addPersonendatenAnschriftProperties(formBuilder, null, one);
  }

  private boolean isDublettenrelevant(Property property) {
    return getPropertyClassesDublettenrelevant().contains(property.getClass());
  }

  protected Collection<Class< ? extends AbstractProperty>> getPropertyClassesDublettenrelevant() {
    return emptyList();
  }

  private void tryAddVerificationMessage(FormBuilder formBuilder, String one, String another) {
    if (isNotBlank(one) && isIdentisch(one, another)) {
      addVerificationMessageIdentisch(formBuilder);
    }
  }

  private boolean isIdentisch(String one, String another) {
    if (isBlank(one)) {
      return isBlank(another);
    }

    return equalsIgnoreCase(one, another);
  }

  private void tryAddVerificationMessage(FormBuilder formBuilder, Object one, Object another) {
    if (one != null && isIdentisch(one, another)) {
      addVerificationMessageIdentisch(formBuilder);
    }
  }

  private boolean isIdentisch(Object one, Object another) {
    if (one == null) {
      return another == null;
    }

    return one.equals(another);
  }

  private FormBuilder addVerificationMessageIdentisch(FormBuilder formBuilder) {
    return formBuilder.withInfoMessage(getMessage("personen.konflikt.dublette.VALUE_IDENTISCH_detail"));
  }

  private Anschrift fixNullToEmptyAnschrift(Personendaten another) {
    if (another != null) {
      return another.getAnschrift();
    }

    return anschriftFactory.create();
  }

  protected boolean isInstanceOf(Personendaten personendaten, Class< ? extends Personendaten> clazz) {
    return personendaten != null && personendaten.isInstanceOf(clazz);
  }
}
