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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

import de.ivu.elect.business.ergebnis.control.GewaehltCreate;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.kandidatur.entity.Ersatzkandidatur;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.personenpruefung.boundary.PersonenPruefungStarter;
import de.ivu.elect.business.personenpruefung.control.CorePersonenPruefungVorbereiter;
import de.ivu.elect.business.personenpruefung.control.KandidaturPruefungAttributeChangedChecker;
import de.ivu.elect.business.protokollierung.entity.LoeschProtokollEvent;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;

@Stateless
public class ErsatzkandidaturEdit extends AbstractErsatzkandidaturEdit {

  @Inject
  protected transient GewaehltCreate gewaehltCreate;

  @Inject
  protected transient KandidaturPruefungAttributeChangedChecker personenPruefungAttributeChangedChecker;

  @Inject
  protected transient CorePersonenPruefungVorbereiter personenPruefungVorbereiter;

  @Inject
  protected transient PersonenPruefungStarter personenPruefungStarter;

  @Inject
  protected transient LoeschProtokollEvent loeschProtokollEvent;

  @Inject
  protected transient GebietNummerFormatter gebietNummerFormatter;

  public ErsatzkandidaturEdit() {
    super();
  }

  @Override
  protected boolean usesMixedTransactionalContexts() {
    // ELECT-945, bspw. GewaehltDAO!
    return true;
  }

  @Override
  public void save(Ersatzkandidatur ersatzkandidatur) {
    verifyCompleteErsatzkandidatur(ersatzkandidatur);

    // NOTE ELECT-2749, dass Änderungen festgestellt werden müssen, bevor die Entität gespeichert wird
    personenPruefungAttributeChangedChecker.bestimmeAttributeChanged(ersatzkandidatur);

    // NOTE that the super implementation performs an ExtendedDao.flush()!
    super.save(ersatzkandidatur);

    // NOTE ELECT-2749, dass die Prüfung vorbereitet werden muss, nachdem die Entität gespeichert wurde
    // NOTE bzgl. attachFresh: ELECT-3187 (Änderungen an Entität werden nicht gespeichert)
    personenPruefungVorbereiter.prepareKandidaturPruefung(dao.refresh(ersatzkandidatur), personenPruefungAttributeChangedChecker);

    personenPruefungStarter.startePersonenPruefung();
  }

  private void verifyCompleteErsatzkandidatur(Ersatzkandidatur ersatzkandidatur) {
    // NOTE ELECT-485, bisher nicht erfasste Ergebnisse werden beim (manuellen) Bearbeiten ggf. neu angelegt.
    for (Gewaehlt gewaehlt : ersatzkandidatur.getGewaehlte()) {
      if (!gewaehlt.isPersistent()) {
        gewaehltCreate.save(gewaehlt);
      }
    }
  }

  @Override
  public void delete(Ersatzkandidatur template) {
    deleteIncludingAllUntergeordneteErsatzkandidaturen(getAttachedEntity(template));
  }

  private void deleteIncludingAllUntergeordneteErsatzkandidaturen(Ersatzkandidatur ersatzkandidatur) {
    for (Ersatzkandidatur untergeordneteErsatzkandidatur : getUntergeordneteErsatzkandidaturenReverseOrdered(ersatzkandidatur)) {
      personenPruefungVorbereiter.deleteAllVerknuepfungenAndMarkVerknuepftePersonenUngeprueft(untergeordneteErsatzkandidatur);

      loeschProtokollEvent.sendeLoeschProtokollEvent(untergeordneteErsatzkandidatur.getWahl(), untergeordneteErsatzkandidatur, "loesch.protokoll.ersatzkandidatur",
          untergeordneteErsatzkandidatur.getGruppe().getName(), gebietNummerFormatter.getDarstellung(untergeordneteErsatzkandidatur.getGebiet()), untergeordneteErsatzkandidatur.getFamilienname(),
          untergeordneteErsatzkandidatur.getRufname());

      super.delete(untergeordneteErsatzkandidatur);
    }

    personenPruefungStarter.startePersonenPruefung();
  }

  private List<Ersatzkandidatur> getUntergeordneteErsatzkandidaturenReverseOrdered(Ersatzkandidatur ersatzkandidatur) {
    List<Ersatzkandidatur> ersatzkandidaturen = new ArrayList<>();

    ersatzkandidaturen.add(ersatzkandidatur);
    ersatzkandidaturen.addAll(ersatzkandidatur.getUntergeordneteErsatzkandidaturen());

    Collections.reverse(ersatzkandidaturen);

    return ersatzkandidaturen;
  }

  public void setStatus(Ersatzkandidatur template, KandidaturStatus kandidaturStatus) {
    Ersatzkandidatur ersatzkandidatur = getAttachedEntity(template);
    ersatzkandidatur.setKandidaturStatus(kandidaturStatus);
  }
}
