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

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

import javax.ejb.Stateless;
import javax.inject.Inject;

import de.ivu.elect.business.konfiguration.boundary.KonfigurationDAO;
import de.ivu.elect.business.konfiguration.entity.ElectKonfigurationWerte;
import de.ivu.elect.business.konfiguration.entity.Konfiguration;
import de.ivu.elect.business.mandant.boundary.MandantDAO;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.person.boundary.PersonendatenDAO;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.PersonendatenPK;
import de.ivu.elect.business.system.boundary.SystemLogWriter;
import de.ivu.elect.business.system.entity.SystemLogQuelle;
import de.ivu.elect.business.wahl.boundary.WahlterminDAO;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.business.wahl.entity.WahlterminPK;
import de.ivu.elect.jee.entity.Entity;


import static de.ivu.elect.business.mandant.entity.EntityPKMitMandant.from;
import static java.util.stream.Collectors.toSet;

@Stateless
public class PersonendatenNamenNormalisiertAktualisieren {

  public static final ElectKonfigurationWerte KONFIGURATION = ElectKonfigurationWerte.ELECT_COMMON_DB_CLEANUP_PERSONENDATEN_NAMEN_NORMALISIERT_AKTUALISIEREN;

  protected static final int ENTITIES_MAX_COUNT_BEFORE_FLUSH = 5000;

  @Inject
  private transient WahlterminDAO wahlterminDAO;

  @Inject
  private transient PersonendatenDAO personendatenDAO;

  @Inject
  private transient KonfigurationDAO konfigurationDAO;

  @Inject
  private transient SystemLogWriter systemLogWriter;

  @Inject
  private transient MandantDAO mandantDAO;

  public PersonendatenNamenNormalisiertAktualisieren() {
    super();
  }

  public void updateNamenNormalisiert() {
    try {
      Collection<WahlterminPK> wahlterminPKs = collectWahltermine().stream().map(Wahltermin::getPk).collect(toSet());

      for (WahlterminPK wahlterminPK : wahlterminPKs) {
        updateNamenNormalisiert(wahlterminPK);
      }
    } finally {
      resetKonfiguration();
    }
  }

  protected void updateNamenNormalisiert(WahlterminPK wahlterminPK) {
    updatePersonendaten(wahlterminPK);
  }

  private void updatePersonendaten(WahlterminPK wahlterminPK) {
    List<PersonendatenPK> personendatenPKs = new ArrayList<>(collectPersonendaten(wahlterminPK).stream().map(Personendaten::getPk).collect(toSet()));

    int anzahl = personendatenPKs.size();
    int anzahlNamenNormalisiertChanged = 0;

    for (int i = 0; i < anzahl; i++) {
      Personendaten personendaten = personendatenDAO.findByPrimaryKey(personendatenPKs.get(i));
      personendaten.setFamilienname(personendaten.getFamilienname());
      personendaten.setFamiliennameBestandteil(personendaten.getFamiliennameBestandteil());
      personendaten.setRufname(personendaten.getRufname());
      personendaten.setVornamen(personendaten.getVornamen());

      if (personendaten.isAttributeChanged()) {
        anzahlNamenNormalisiertChanged++;
      }

      if (i % ENTITIES_MAX_COUNT_BEFORE_FLUSH == 0) {
        personendatenDAO.flush();
        personendatenDAO.clear();
      }
    }

    writeSystemLog(wahlterminPK, Personendaten.class, anzahl, anzahlNamenNormalisiertChanged);

    return;
  }

  private void writeSystemLog(WahlterminPK wahlterminPK, Class<? extends Entity<?, ?>> entityClass, int anzahl, int anzahlGeaendert) {
    systemLogWriter.writeInfoLogMessageFuerMandant(from(wahlterminPK),
        "Namen erneut normalisiert [wahltermin = " + wahlterminPK.getId() + ", art = " + entityClass.getSimpleName() + ", anzahl gesamt = " + anzahl
            + ", anzahl aktualisiert = " + anzahlGeaendert + "]", SystemLogQuelle.DB_CLEANUP);
  }

  private void resetKonfiguration() {
    Konfiguration konfiguration = konfigurationDAO.findBySystemSchluessel(KONFIGURATION.getKey());
    konfiguration.setWert(Boolean.FALSE.toString());
  }

  private Collection<Personendaten> collectPersonendaten(WahlterminPK wahlterminPK) {
    return personendatenDAO.findByWahltermin(attach(wahlterminPK));
  }

  private Collection<Wahltermin> collectWahltermine() {

    Collection<Wahltermin> result = new ArrayList<>();
    for (Mandant mandant : mandantDAO.findByAll()) {
      if (mandant.getArt().isCustomerMandant() && mandant.getStatus().isAktiv()) {
        result.addAll(wahlterminDAO.findByAll(mandant));
      }
    }
    return result;

  }

  protected Wahltermin attach(WahlterminPK wahlterminPK) {
    return wahlterminDAO.findByPrimaryKey(wahlterminPK);
  }
}
