
package de.ivu.elect.business.wertelisten.boundary;

import static com.querydsl.core.types.dsl.Expressions.anyOf;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.enterprise.event.TransactionPhase;
import javax.inject.Inject;

import com.querydsl.jpa.impl.JPAQuery;

import de.ivu.elect.business.person.boundary.PersonendatenDAO;
import de.ivu.elect.business.person.entity.AbstractPersonendaten;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.QPersonendaten;
import de.ivu.elect.business.personenpruefung.boundary.PersonenKonfliktEdit;
import de.ivu.elect.business.personenpruefung.boundary.PersonenPruefungStarter;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wertelisten.control.WertelistenUpdatedEvent;
import de.ivu.elect.business.wertelisten.entity.WertelistenArt;
import de.ivu.elect.jee.exception.ElectCommonException;

@Stateless
public class PersonenKonfliktZuruecksetzerOnWertelistenUpdateEvent implements Serializable {

  private static final long serialVersionUID = 1L;

  protected static final String ATTRIBUTE_AS_LIST_SEPARATOR = AbstractPersonendaten.ATTRIBUTE_AS_LIST_SEPARATOR;

  @Inject
  private PersonenKonfliktEdit personenKonfliktEdit;

  @Inject
  private PersonenPruefungStarter personenPruefungStarter;

  @Inject
  private PersonendatenDAO personendatenDao;

  public PersonenKonfliktZuruecksetzerOnWertelistenUpdateEvent() {
    super();
  }

  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  public void listen(@Observes(during = TransactionPhase.AFTER_SUCCESS, notifyObserver = Reception.ALWAYS) WertelistenUpdatedEvent event) {
    if (event.getWahl() == null) {
      throw new ElectCommonException("Ändern von Wertelisten Kann nur bei zur Bearbeitung ausgewählter Wahl durchgeführt werden!");
    }

    if (event.getOldValue() == null) {
      if (event.getNewValue() == null) {
        return; // Event ohne veränderte Werte nichts zu tun
      }
      // Wert wurde angelegt
      postWertelistenCreate(event.getNewValue(), event.getWertelistenArt(), event.getWahl());

    } else if (event.getNewValue() == null) {
      // Wert wurde gelöscht
      postWertelistenDelete(event.getOldValue(), event.getWertelistenArt(), event.getWahl());

    } else {
      // Wert wurde umbenannt
      postWertelistenChange(event.getOldValue(), event.getNewValue(), event.getWertelistenArt(), event.getWahl());

    }

    // Starte Prüfung
    personenPruefungStarter.startePersonenPruefung();
  }

  private void postWertelistenChange(String oldValue, String newValue, WertelistenArt wertelistenArt, Wahl wahl) {
    if (!newValue.equals(oldValue)) {
      postWertelistenDelete(oldValue, wertelistenArt, wahl);
      postWertelistenCreate(newValue, wertelistenArt, wahl);
    }
  }

  private void postWertelistenCreate(String newValue, WertelistenArt wertelistenArt, Wahl wahl) {
    List< ? extends Personendaten> personenMitNeuemWert = new ArrayList<>();
    switch (wertelistenArt) {
      case AKADEMISCHER_GRAD :
        personenMitNeuemWert = findePersonenMitAkademischemGrad(newValue, wahl);
        break;

      case EHRENAMT :
        personenMitNeuemWert = findePersonenMitEhrenamt(newValue, wahl);
        break;
    }

    personenKonfliktEdit.resetPersonenKonfliktWertelistenAbgleichManuellZuPruefen(wahl, personenMitNeuemWert);
  }

  private void postWertelistenDelete(String oldValue, WertelistenArt wertelistenArt, Wahl wahl) {
    List< ? extends Personendaten> personenMitAltemWert = new ArrayList<>();
    switch (wertelistenArt) {
      case AKADEMISCHER_GRAD :
        personenMitAltemWert = findePersonenMitAkademischemGrad(oldValue, wahl);
        break;

      case EHRENAMT :
        personenMitAltemWert = findePersonenMitEhrenamt(oldValue, wahl);
        break;
    }

    personenKonfliktEdit.deletePersonenKonfliktWertelistenAbgleichAndSetPersonStatusUngeprueft(personenMitAltemWert);
  }

  /*
   * Feld kann mehrere akademische Grade mit Trennzeichen enthalten. Suche nach stimmt vollständig überein, steht am
   * Anfang, steht am End oder steht in der Mitte.
   */
  protected List< ? extends Personendaten> findePersonenMitAkademischemGrad(String akademischerGrad, Wahl wahl) {
    QPersonendaten personendatenTable = QPersonendaten.personendaten;
    JPAQuery query = personendatenDao.getQueryDsl().from(personendatenTable).getQuery();

    query.where(personendatenTable.wahl.eq(wahl),
        anyOf(personendatenTable.akademischerGradUnformatiert.eq(akademischerGrad),
            personendatenTable.akademischerGradUnformatiert.startsWith(akademischerGrad + ATTRIBUTE_AS_LIST_SEPARATOR),
            personendatenTable.akademischerGradUnformatiert.endsWith(ATTRIBUTE_AS_LIST_SEPARATOR + akademischerGrad),
            personendatenTable.akademischerGradUnformatiert
                .like(ATTRIBUTE_AS_LIST_SEPARATOR + akademischerGrad + ATTRIBUTE_AS_LIST_SEPARATOR)));

    return query.fetch();
  }

  /*
   * Nur Kandidaturen haben Ehrenämter. Methode muss vom WUS zu überschrieben werden.
   */
  protected List< ? extends Personendaten> findePersonenMitEhrenamt(String ehrenamt, Wahl wahl) {
    return new ArrayList<>();
  }
}
