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

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.ergebnis.control.GewaehltCreate;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
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.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;

@Stateless
public class ListenkandidaturEdit extends AbstractListenkandidaturEdit {

  @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;

  @Inject
  protected transient ErsatzkandidaturEdit ersatzkandidaturEdit;

  @Inject
  protected transient ListenkandidaturListenpositionResolver listenpositionResolver;

  public ListenkandidaturEdit() {
    super();
  }

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

  @Override
  public void save(Listenkandidatur listenkandidatur) {
    verifyCompleteListenkandidatur(listenkandidatur);

    updateAnzahlNennungen(listenkandidatur);

    updateListenpositionen(listenkandidatur.getListe(), listenkandidatur);

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

    // NOTE that the super implementation performs an ExtendedDao.flush()!
    plainSave(listenkandidatur);

    // 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(listenkandidatur), personenPruefungAttributeChangedChecker);

    personenPruefungStarter.startePersonenPruefung();
  }

  protected void plainSave(Listenkandidatur listenkandidatur) {
    super.save(listenkandidatur);
  }

  private void updateAnzahlNennungen(Listenkandidatur listenkandidatur) {
    if (listenkandidatur.getListenkandidaturArt().isErsatzkandidatur()) {
      listenkandidatur.setAnzahlNennungen(0L);
    }
  }

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

  public void delete(Collection<Listenkandidatur> listenkandidaturen) {
    for (Listenkandidatur listenkandidatur : new ArrayList<>(listenkandidaturen)) {
      delete(listenkandidatur);
    }
  }

  @Override
  public void delete(Listenkandidatur template) {
    Listenkandidatur listenkandidatur = getAttachedEntity(template);

    loeschProtokollEvent.sendeLoeschProtokollEvent(listenkandidatur.getWahl(), listenkandidatur, "loesch.protokoll.listenkandidatur", listenkandidatur.getListe().getGruppe().getName(),
        gebietNummerFormatter.getDarstellung(listenkandidatur.getGebiet()), longToString(listenkandidatur.getRelativePosition()));

    deleteIncludingAllUntergeordneteErsatzkandidaturen(listenkandidatur); // ELECT-9845, zunächst alle Ersatzkandidaturen löschen...

    boolean listenkandidaturAufStimmzettelDeleted = listenkandidatur.isAufStimmzettel();

    Liste liste = listenkandidatur.getListe();
    liste.removeListenkandidatur(listenkandidatur);

    if (liste.isZugelassen() && listenkandidaturAufStimmzettelDeleted) {
      liste.setWahlvorschlagStatus(liste.getWahlvorschlagStatusInitial());
    }

    updateListenpositionen(liste);
  }

  private static String longToString(Long relativePosition) {
    if (relativePosition == null) {
      return "";
    }

    return Long.toString(relativePosition);
  }

  private void deleteIncludingAllUntergeordneteErsatzkandidaturen(Listenkandidatur listenkandidatur) {
    if (listenkandidatur.hasZugeordneteErsatzkandidatur()) {
      ersatzkandidaturEdit.delete(listenkandidatur.getZugeordneteErsatzkandidatur());
    }

    personenPruefungVorbereiter.deleteAllVerknuepfungenAndMarkVerknuepftePersonenUngeprueft(listenkandidatur);

    super.delete(listenkandidatur);

    personenPruefungStarter.startePersonenPruefung();
  }

  private void updateListenpositionen(Liste liste) {
    listenpositionResolver.updateListenpositionen(liste);
  }

  private void updateListenpositionen(Liste liste, Listenkandidatur listenkandidatur) {
    listenpositionResolver.updateListenpositionen(liste, listenkandidatur);
  }

  public void listenpositionenSetzenUndSpeichern(List<Listenkandidatur> listenkandidaturen) {
    for (int i = 0; i < listenkandidaturen.size(); i++) {
      Listenkandidatur listenkandidatur = extendedDao.attach(listenkandidaturen.get(i));
      listenkandidatur.setRelativePosition(i + 1L);
    }
  }

  public void setStatus(Listenkandidatur template, KandidaturStatus kandidaturStatus, String kandidaturStatusBemerkung) {
    Listenkandidatur listenkandidatur = getAttachedEntity(template);
    listenkandidatur.setKandidaturStatus(kandidaturStatus);
    listenkandidatur.setBemerkung(kandidaturStatusBemerkung);
  }
}
