
package de.ivu.elect.business.person.control;

import static de.ivu.elect.jee.entity.EntityUtil.normalizeDate;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.apache.commons.lang3.StringUtils.equalsAnyIgnoreCase;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.person.entity.Geschlecht;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.staat.entity.Staat;

public abstract class AbstractPersonenVergleichFunktion<T extends Personendaten> implements PersonenVergleichFunktion<T> {

  protected PersonendatenMapCreator personendatenMapCreator;

  protected AbstractPersonenVergleichFunktion() {
    super();

    this.personendatenMapCreator = new PersonendatenMapCreator();
  }

  protected Collection<List<T>> collectGroupsOfPersonendatenSharingSameOrdnungsmerkmal(Collection< ? extends T> personendaten) {
    Map<String, List<T>> personendatenPerOrdnungsmerkmal = personendatenMapCreator.personenNachOrdnungsmerkmal(personendaten);

    return personendatenPerOrdnungsmerkmal.values();
  }

  protected Collection<List<T>> collectGroupsOfPersonendatenSharingSameFamilienname(Collection< ? extends T> personendaten) {
    Map<String, List<T>> personendatenPerName = personendatenMapCreator.personenNachFamiliennameNormalisiert(personendaten);

    if (personendatenPerName.isEmpty()) {
      personendatenPerName = personendatenMapCreator.personenNachFamilienname(personendaten);
    }

    return personendatenPerName.values();
  }

  protected Collection<List<T>> collectGroupsOfPersonendatenSharingSameRufname(Collection< ? extends T> personendaten) {
    Map<String, List<T>> personendatenPerName = personendatenMapCreator.personenNachRufnameNormalisiert(personendaten);

    if (personendatenPerName.isEmpty()) {
      personendatenPerName = personendatenMapCreator.personenNachRufname(personendaten);
    }

    return personendatenPerName.values();
  }

  protected Collection<List<T>> collectGroupsOfPersonendatenSharingSameVornamen(Collection< ? extends T> personendaten) {
    Map<String, List<T>> personendatenPerName = personendatenMapCreator.personenNachVornamenNormalisiert(personendaten);

    if (personendatenPerName.isEmpty()) {
      personendatenPerName = personendatenMapCreator.personenNachVornamen(personendaten);
    }

    return personendatenPerName.values();
  }

  protected Collection<List<T>> collectGroupsOfPersonendatenSharingSameGeburtsdatum(Collection< ? extends T> personendaten) {
    Map<Date, List<T>> personendatenPerGeburtsdatum = personendatenMapCreator.personenNachGeburtsdatum(personendaten);

    return personendatenPerGeburtsdatum.values();
  }

  protected Collection<List<T>> collectGroupsOfPersonendatenSharingSameGeschlecht(Collection< ? extends T> personendaten) {
    Map<Geschlecht, List<T>> personendatenPerGeschlecht = personendatenMapCreator.personenNachGeschlecht(personendaten);

    return personendatenPerGeschlecht.values();
  }

  protected boolean isNoneBlankOrdnungsmerkmal(T one, T another) {
    return one.hasOrdnungsmerkmal() && another.hasOrdnungsmerkmal();
  }

  protected boolean isPersonenIdentischNachOrdnungsmerkmal(T one, T another) {
    return isNoneBlankOrdnungsmerkmal(one, another) && isIdentisch(one.getOrdnungsmerkmal(), another.getOrdnungsmerkmal());
  }

  protected boolean isAllBlankOrIdentischTitel(T one, T another) {
    return isAllBlankOrIdentisch(one.getTitel(), another.getTitel());
  }

  protected boolean isAllBlankOrIdentischFamilienname(T one, T another) {
    return isAllBlankOrIdentisch(one.getFamilienname(), another.getFamilienname());
  }

  protected boolean isAllBlankOrAehnlichFamilienname(T one, T another) {
    return isNoneBlankAndAehnlich(one.getFamiliennameNormalisiert(), another.getFamiliennameNormalisiert()) || isAllBlankOrAehnlich(one.getFamilienname(), another.getFamilienname());
  }

  protected boolean isAnyBlankOrAehnlichFamilienname(T one, T another) {
    return isNoneBlankAndAehnlich(one.getFamiliennameNormalisiert(), another.getFamiliennameNormalisiert()) || isAnyBlankOrAehnlich(one.getFamilienname(), another.getFamilienname());
  }

  protected boolean isNoneBlankAndAehnlichFamilienname(T one, T another) {
    return isNoneBlankAndAehnlich(one.getFamiliennameNormalisiert(), another.getFamiliennameNormalisiert()) || isNoneBlankAndAehnlich(one.getFamilienname(), another.getFamilienname());
  }

  protected boolean isAllBlankOrIdentischFamiliennameBestandteil(T one, T another) {
    return isAllBlankOrIdentisch(one.getFamiliennameBestandteil(), another.getFamiliennameBestandteil());
  }

  protected boolean isAllBlankOrIdentischVornamen(T one, T another) {
    return isAllBlankOrIdentisch(one.getVornamen(), another.getVornamen());
  }

  protected boolean isAllBlankOrIdentischRufname(T one, T another) {
    return isAllBlankOrIdentisch(one.getRufname(), another.getRufname());
  }

  protected boolean isAllBlankOrAehnlichRufname(T one, T another) {
    return isNoneBlankAndAehnlich(one.getRufnameNormalisiert(), another.getRufnameNormalisiert()) || isAllBlankOrAehnlich(one.getRufname(), another.getRufname());
  }

  protected boolean isAllBlankOrIdentischGeburtsdatum(T one, T another) {
    return isAllNull(one.getGeburtsdatum(), another.getGeburtsdatum()) || isIdentisch(one.getGeburtsdatum(), another.getGeburtsdatum());
  }

  protected boolean isAnyBlankOrIdentischGeburtsdatum(T one, T another) {
    return isAnyNull(one.getGeburtsdatum(), another.getGeburtsdatum()) || isIdentisch(one.getGeburtsdatum(), another.getGeburtsdatum());
  }

  protected boolean isAllBlankOrAehnlichGeburtsdatum(T one, T another) {
    return isAllNull(one.getGeburtsdatum(), another.getGeburtsdatum()) || isAehnlich(one.getGeburtsdatum(), another.getGeburtsdatum());
  }

  protected boolean isAnyBlankOrAehnlichGeburtsdatum(T one, T another) {
    return isAnyNull(one.getGeburtsdatum(), another.getGeburtsdatum()) || isAehnlich(one.getGeburtsdatum(), another.getGeburtsdatum());
  }

  protected boolean isNoneBlankAndAehnlichGeburtsdatum(T one, T another) {
    return isNoneNull(one.getGeburtsdatum(), another.getGeburtsdatum()) && isAehnlich(one.getGeburtsdatum(), another.getGeburtsdatum());
  }

  protected boolean isAllBlankOrIdentischGeschlecht(T one, T another) {
    return isAllNull(one.getGeschlecht(), another.getGeschlecht()) || isIdentisch(one.getGeschlecht(), another.getGeschlecht());
  }

  protected boolean isAnyBlankOrAehnlichGeschlecht(T one, T another) {
    return isAnyNull(one.getGeschlecht(), another.getGeschlecht()) || isAehnlich(one.getGeschlecht(), another.getGeschlecht());
  }

  protected boolean isNoneBlankAndAehnlichGeschlecht(T one, T another) {
    return isNoneNull(one.getGeschlecht(), another.getGeschlecht()) && isAehnlich(one.getGeschlecht(), another.getGeschlecht());
  }

  protected boolean isAllBlankOrIdentischStaatsangehoerigkeit(T one, T another) {
    return isIdentisch(collectStaatsangehoerigkeitenSorted(one), collectStaatsangehoerigkeitenSorted(another));
  }

  protected List<Staat> collectStaatsangehoerigkeitenSorted(T personendaten) {
    return personendaten.getStaatsangehoerigkeitenSorted();
  }

  protected boolean isAllBlankOrIdentischKuenstlername(T one, T another) {
    return isAllBlankOrIdentisch(one.getKuenstlername(), another.getKuenstlername());
  }

  protected boolean isAllNull(Object one, Object another) {
    return isNull(one) && isNull(another);
  }

  protected boolean isAnyNull(Object one, Object another) {
    return isNull(one) || isNull(another);
  }

  protected boolean isNoneNull(Object one, Object another) {
    return nonNull(one) && nonNull(another);
  }

  private boolean isAllBlankOrIdentisch(String one, String another) {
    return isAllBlank(one, another) || isIdentisch(one, another);
  }

  private boolean isAllBlankOrAehnlich(String one, String another) {
    return isAllBlank(one, another) || isAehnlich(one, another);
  }

  private boolean isAnyBlankOrAehnlich(String one, String another) {
    return isAnyBlank(one, another) || isAehnlich(one, another);
  }

  private boolean isNoneBlankAndAehnlich(String one, String another) {
    return isNoneBlank(one, another) && isAehnlich(one, another);
  }

  private boolean isNoneBlank(String one, String another) {
    return StringUtils.isNoneBlank(one, another);
  }

  private boolean isAnyBlank(String one, String another) {
    return StringUtils.isAnyBlank(one, another);
  }

  private boolean isAllBlank(String one, String another) {
    return StringUtils.isAllBlank(one, another);
  }

  private boolean isIdentisch(String one, String another) {
    return trimToEmpty(one).equals(trimToEmpty(another));
  }

  private boolean isIdentisch(Date one, Date another) {
    return Objects.equals(normalizeDate(one), normalizeDate(another));
  }

  private boolean isIdentisch(Object one, Object another) {
    return Objects.equals(one, another);
  }

  private boolean isAehnlich(String one, String another) {
    return trimToEmpty(one).equalsIgnoreCase(trimToEmpty(another));
  }

  private boolean isAehnlich(Date one, Date another) {
    try {
      String oneDayMonthFormatted = new SimpleDateFormat("ddMMyyyy").format(one);
      String oneMonthDayFormatted = new SimpleDateFormat("MMddyyyy").format(one);

      String anotherDayMonthFormatted = new SimpleDateFormat("ddMMyyyy").format(another);

      if (equalsAnyIgnoreCase(anotherDayMonthFormatted, oneDayMonthFormatted, oneMonthDayFormatted)) { // ELECT-12958
        return true;
      }
    } catch (Exception ignored) {
    }

    return Objects.equals(normalizeDate(one), normalizeDate(another));
  }

  private boolean isAehnlich(Object one, Object another) {
    return Objects.equals(one, another);
  }
}
