
package de.ivu.elect.business.personenpruefung.boundary.dubletten;

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

import javax.inject.Inject;

import org.apache.deltaspike.core.api.scope.ConversationGroup;

import de.ivu.elect.business.person.boundary.PersonendatenDAO;
import de.ivu.elect.business.person.entity.PersonenVerknuepfung;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.person.entity.PersonendatenPK;
import de.ivu.elect.business.person.entity.VerknuepfungsStatus;
import de.ivu.elect.business.personenpruefung.control.dubletten.AbstractPersonenDublettenZulaessigkeitPruefer;

/**
 * Speichert und verwaltet alle PersonendatenPK, die ursprünglich an den View zur Bearbeitung übergeben wurden. Geht sukzessiv alle bekannten PersonendatenPK durch und sucht für den jeweils aktuellen
 * PersonendatenPK alle relevanten Verknüpfungen.
 */
public abstract class AbstractPersonenKonfliktDublettenQueueConversationSelect {

  @Inject
  protected transient PersonendatenDAO personendatenDao;

  @Inject
  @ConversationGroup(PersonenKonfliktDublettenQueueConversationStore.class)
  protected transient PersonenKonfliktDublettenQueueConversationStore conversationStore;

  @Inject
  @ConversationGroup(DublettenSearchParameters.class)
  protected transient DublettenSearchParameters searchParameters;

  public AbstractPersonenKonfliktDublettenQueueConversationSelect() {
    super();
  }

  public boolean isSelected() {
    return getPersonenVerknuepfungZuBearbeiten() != null;
  }

  public PersonenVerknuepfung getPersonenVerknuepfungZuBearbeiten() {
    while (hasPersonendatenPkZuBearbeiten()) {
      Personendaten personendatenZuBearbeiten = personendatenDao.findByPrimaryKey(getPersonendatenPkZuBearbeiten());

      if (personendatenZuBearbeiten == null) {
        selectNextPersonendatenPkZuBearbeiten();

        // Aktuelle Personendaten nicht mehr gültig -> Abbruch und neuer Durchlauf mit nächsten Personendaten.
        continue;
      }

      PersonenVerknuepfung personenVerknuepfungZuBearbeiten = findPersonenVerknuepfungZuBearbeiten(personendatenZuBearbeiten);

      if (personenVerknuepfungZuBearbeiten == null) {
        selectNextPersonendatenPkZuBearbeiten();

        // Aktuelle Personendaten haben keine zu bearbeitende Verknüpfung mehr -> Abbruch und neuer Durchlauf mit nächsten Personendaten.
        continue;
      }

      return personenVerknuepfungZuBearbeiten;
    }

    return null;
  }

  public void selectNextPersonenVerknuepfungZuBearbeiten(Collection<VerknuepfungsStatus> verknuepfungsStatusZuBearbeiten) {
    PersonenVerknuepfung personenVerknuepfungZuBearbeiten = null;

    do {
      personenVerknuepfungZuBearbeiten = getPersonenVerknuepfungZuBearbeiten();

      if (personenVerknuepfungZuBearbeiten != null) {
        conversationStore.addPersonenVerknuepfungPkBearbeitet(personenVerknuepfungZuBearbeiten.getPk());
      }
    } while (isNextPersonenVerknuepfungZuBearbeitenIrrelevant(personenVerknuepfungZuBearbeiten, verknuepfungsStatusZuBearbeiten));
  }

  private boolean isNextPersonenVerknuepfungZuBearbeitenIrrelevant(PersonenVerknuepfung personenVerknuepfungZuBearbeitenZuvor, Collection<VerknuepfungsStatus> verknuepfungsStatusZuBearbeiten) {
    PersonenVerknuepfung personenVerknuepfungZuBearbeitenAktuell = getPersonenVerknuepfungZuBearbeiten();

    return personenVerknuepfungZuBearbeitenAktuell != null && (personenVerknuepfungZuBearbeitenAktuell.equals(personenVerknuepfungZuBearbeitenZuvor)
        || !verknuepfungsStatusZuBearbeiten.contains(personenVerknuepfungZuBearbeitenAktuell.getVerknuepfungsStatus()));
  }

  private PersonenVerknuepfung findPersonenVerknuepfungZuBearbeiten(Personendaten personendaten) {
    for (PersonenVerknuepfung personenVerknuepfung : personendaten.getPersonenVerknuepfungen()) {
      if (isPersonenVerknuepfungZuBearbeiten(personenVerknuepfung)) {
        return personenVerknuepfung;
      }
    }

    return null;
  }

  protected boolean isPersonenVerknuepfungZuBearbeiten(PersonenVerknuepfung personenVerknuepfung) {
    return !isPersonenVerknuepfungBearbeitet(personenVerknuepfung) && matchesSearchParameters(personenVerknuepfung) && !isZulaessigePersonenVerknuepfung(personenVerknuepfung);
  }

  private boolean isPersonenVerknuepfungBearbeitet(PersonenVerknuepfung personenVerknuepfung) {
    return conversationStore.isPersonenVerknuepfungPkBearbeitet(personenVerknuepfung.getPk());
  }

  private boolean matchesSearchParameters(PersonenVerknuepfung personenVerknuepfung) {
    return searchParameters.getVerknuepfungsStatus().contains(personenVerknuepfung.getVerknuepfungsStatus())
        && searchParameters.getVerknuepfungsGrundlage().contains(personenVerknuepfung.getVerknuepfungsGrundlage());
  }

  private boolean isZulaessigePersonenVerknuepfung(PersonenVerknuepfung personenVerknuepfung) {
    return getPersonenDublettenZulaessigkeitPruefer().isZulaessigeDublette(personenVerknuepfung);
  }

  protected abstract AbstractPersonenDublettenZulaessigkeitPruefer getPersonenDublettenZulaessigkeitPruefer();

  public void setPersonendatenPksZuBearbeiten(List<PersonendatenPK> personendatenPks) {
    for (PersonendatenPK personendatenPk : personendatenPks) {
      conversationStore.addPersonendatenPkZuBearbeiten(personendatenPk);
    }
  }

  private boolean hasPersonendatenPkZuBearbeiten() {
    return conversationStore.hasPersonendatenPkZuBearbeiten();
  }

  private PersonendatenPK getPersonendatenPkZuBearbeiten() {
    return conversationStore.getPersonendatenPkZuBearbeiten();
  }

  private PersonendatenPK selectNextPersonendatenPkZuBearbeiten() {
    return conversationStore.selectNextPersonendatenPkZuBearbeiten();
  }

  public void clear() {
    conversationStore.close();
  }
}
