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

import de.ivu.elect.business.ergebnis.control.StimmenHochrechner;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.ErgebnisStatus;
import de.ivu.elect.business.ergebnis.entity.Ergebnisart;
import de.ivu.elect.business.ergebnis.entity.Stimmen;
import de.ivu.elect.business.sitzberechnung.control.Sitzberechnung;
import de.ivu.elect.business.sitzberechnung.entity.SitzberechnungsalgorithmusKonfiguration;
import de.ivu.elect.business.wahl.entity.Wahl;

import javax.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 *  on 18.02.2016.
 */
@Deprecated // Klasse überdenken, führt bei großen Gebietsbäumen ganz sicher zu Performance-Problemen
public class HochrechnungErgebnisberechnung {

  @Inject
  ErgebnisDAO ergebnisDAO;

  @Inject
  StimmenDAO stimmenDAO;

  @Inject
  StimmenHochrechner stimmenHochrechner;

  @Inject
  Sitzberechnung sitzberechnung;

  /**
   * Wenn ein Vorperode-Ergebnis vorliegt, erzeuge eine Kopie von ergebnis und ergänze dieses um hochgerechnete
   * Stimmergebnisse und führe damit eine Sitzberechnung durch. Wenn kein Vorperiode-Ergebnis vorliegt, dann tue nichts.
   * 
   * @param ergebnis
   *          das aktuelle Ergebnis (vorläufig oder endgültig), auf dessen Grundlage eine Hochrechnung erstellt werden
   *          soll
   */
  public void fuehreHochrechnungDurchWennMoeglich(Ergebnis ergebnis, String ausloeser,
      SitzberechnungsalgorithmusKonfiguration konfiguration) {
    Collection<Stimmen> vorperiodenStimmen = getVorperiodenStimmen(ergebnis.getWahl());
    if (!vorperiodenStimmen.isEmpty()) {
      berechneHochrechnung(ergebnis, ausloeser, konfiguration, vorperiodenStimmen);
    }
  }

  private Collection<Stimmen> getVorperiodenStimmen(Wahl wahl) {
    List<Ergebnis> ergebnisseVorperiode = ergebnisDAO.findByWahlAndErgebnisart(wahl, Ergebnisart.VORPERIODE);
    if (ergebnisseVorperiode.isEmpty()) {
      return Collections.emptyList();
    }
    Ergebnis ergebnisVorperiode = ergebnisseVorperiode.get(0);
    List<Stimmen> stimmenVorperiode = stimmenDAO.findByErgebnisNoCache(ergebnisVorperiode);
    return stimmenVorperiode;
  }

  /**
   * Erzeugt ein persistentes Ergebnis-Objekt, kopiert da hinein die Stimmen von ergebnis, ergänzt diese Stimmen, indem
   * eine Hochrechnung der fehlenden Stimmen durchgeführt wird und führt zum Schluss eine Sitzberechnung mit den Stimmen
   * durch, die bei der Hochrechnung herauskommen.
   */
  private void berechneHochrechnung(Ergebnis ergebnis, String ausloeser,
      SitzberechnungsalgorithmusKonfiguration konfiguration, Collection<Stimmen> vorperiodenStimmen) {
    Ergebnis ergebnisFuerHochrechnung = createErgebnisFuerDieHochrechnung(ergebnis);
    setzeZeitpunktUndAusloeser(ausloeser, ergebnisFuerHochrechnung);
    stimmenHochrechner.ergaenzeHochgerechneteStimmen(ergebnis, ergebnisFuerHochrechnung, vorperiodenStimmen);
    sitzberechnung.berechneSitze(ergebnisFuerHochrechnung, konfiguration);
  }

  /**
   * Erzeugt eine persistente Kopie von ergebnis, in der die Hochrechnung gespeichert wird
   */
  private Ergebnis createErgebnisFuerDieHochrechnung(Ergebnis ergebnis) {
    Ergebnis result = new Ergebnis();
    result.setWahl(ergebnis.getWahl());
    Ergebnisart ergebnisart = ergebnis.getErgebnisart().isEndgueltig()
        ? Ergebnisart.HOCHRECHNUNG_ENDGUELTIG
        : Ergebnisart.HOCHRECHNUNG_VORLAEUFIG;
    result.setErgebnisart(ergebnisart);
    result.setErgebnisStatus(ErgebnisStatus.ZU_BERECHNEN);
    result.setName(ergebnis.getName()); // TODO: Vielleicht ein eigener Name???
    result.setEingangssequenznummer(ergebnis.getEingangssequenznummer());
    result.setSitzberechnungsalgorithmus(ergebnis.getSitzberechnungsalgorithmus());
    ergebnisDAO.persist(result);

    return result;
  }

  private void setzeZeitpunktUndAusloeser(String ausloeser, Ergebnis ergebnis) {
    ergebnis.setAusloeser(ausloeser);
    ergebnis.setZeitstempel(new Date());
  }

}
