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

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

import javax.annotation.Nullable;

import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Stimmen;
import de.ivu.elect.business.stimmeingabe.entity.StimmenLadenArt;
import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;

/**
 *  on 17.02.2016.
 */
@Deprecated // Implementierung zu speziell, de.ivu.elect.business.hochrechnung.boundary.HochrechnungsalgorithmusFinder nutzen
public class StimmenVergleichsHochrechner extends AbstractStimmenHochrechner {

  /**
   * Füllt das ergebnisFuerHochrechnung mit Stimmen-Objekten. Dies erfolgt nur für die Gebiete, für die auch beim
   * aktuellen Ergebnis ein Ergebniseingang vorliegt.
   *
   * @param ergebnis
   *          das aktuelle, meist noch unvollständige Ergebnis
   * @param ergebnisFuerHochrechnung
   *          das Ergebnis für die Hochrechnung
   * @param vorperiodenStimmen
   *          die Stimmen-Objekte der Vorperiode
   */
  public void ergaenzeHochgerechneteStimmen(Ergebnis ergebnis, Ergebnis ergebnisFuerHochrechnung,
      Collection<Stimmen> vorperiodenStimmen) {
    StimmergebnisDaten stimmergebnisDaten = stimmergebnisDatenCreator.createErgebnisDatenSitzberechnung(ergebnis);
    StimmenFuerHochrechnung stimmenFuerHochrechnung = new StimmenFuerHochrechnung(stimmergebnisDaten,
        vorperiodenStimmen);

    Set<Gebiet> erfassteGebiete = stimmergebnisDaten.getErfassteGebiete();
    for (Wahldurchfuehrungsgebiet gebiet : stimmergebnisDaten.getErfassungsgebiete()) {
      if (erfassteGebiete.contains(gebiet)) {
        hochrechneStimmenVonErfassungsgebiet(gebiet, stimmenFuerHochrechnung, stimmergebnisDaten,
            ergebnisFuerHochrechnung);
      }
    }
  }

  /**
   * Hochrechnung für Stimmen einer Stimmenart (LISTENSTIMME oder DIREKTSTIMME) für eine Gruppe in einem
   * Erfassungsgebiet, für das ein Ergebnis eingegangen ist. Betrachtet wird jedoch das Ergebnis OHNE dieses Gebiet. Es
   * werden der Reihe nach die übergeordneten Gebiete durchprobiert für die folgenden beiden Prognosen: 1.
   * StimmenKumuliert * StimmenVorperiode / StimmenVorperiodeKumuliert (also jeweils bezogen auf die jeweilige Gruppe)
   * und 2. StimmenKumuliert * GueltigeStimmenVorperiode / GueltigeStimmenVorperiodeKumuliert (d.h. wenn die Gruppe auf
   * dem Gebiet keine Vorperioden-Werte hat, dann werden alle gültigen Stimmen zum Gewichten herangezogen). Die
   * kumulierten Werte sind immer vom übergeordneten Gebiet, die Vorperioden-Werte von hochzurechnenden
   * Erfassungsgebiet.
   *
   * @param gruppe
   *          für diese Gruppe wird hochgerechnet
   * @param gueltige
   *          die Systemgruppe der gültigen Stimmen
   * @param gebiet
   *          für dieses Gebiet wird hochgerechnet
   * @param uebergeordneteGebiete
   *          sind die Gebiete oberhalb von gebiet bis zur Wurzel
   * @param stimmenart
   *          DIREKTSTIMME oder LISTENSTIMME @return eine Prognose für das Stimmenergebnis der gruppe auf dem gebiet,
   *          oder null, falls keine Prognose möglich war
   */
  @Override
  protected @Nullable Long getHochgerechneteStimmen(Gruppe gruppe, Gruppe gueltige, Wahldurchfuehrungsgebiet gebiet,
      List<Wahldurchfuehrungsgebiet> uebergeordneteGebiete, Stimmenart stimmenart,
      StimmenFuerHochrechnung stimmenFuerHochrechnung) {
    Long stimmenVorperiode = stimmenFuerHochrechnung.getStimmenVorperiode(gruppe, gebiet, stimmenart).get();
    Long stimmenAktuell = stimmenFuerHochrechnung.getStimmenAktuell(gruppe, gebiet, stimmenart).get();
    Long gueltigeStimmenVorperiode = stimmenFuerHochrechnung.getGueltigeStimmenVorperiode(gueltige, gebiet, stimmenart)
        .get();

    for (Wahldurchfuehrungsgebiet uebergeordnetesGebiet : uebergeordneteGebiete) {
      Long prognose = berechnePrognose(
          () -> stimmenFuerHochrechnung.getStimmenKumuliert(gruppe, uebergeordnetesGebiet, stimmenart)
              .minus(stimmenAktuell),
          stimmenVorperiode, () -> stimmenFuerHochrechnung
              .getStimmenVorperiodeKumuliert(gruppe, uebergeordnetesGebiet, stimmenart).minus(stimmenVorperiode));
      if (prognose != null) {
        return prognose;
      }

      prognose = berechnePrognose(
          () -> stimmenFuerHochrechnung.getStimmenKumuliert(gruppe, uebergeordnetesGebiet, stimmenart)
              .minus(stimmenAktuell),
          gueltigeStimmenVorperiode,
          () -> stimmenFuerHochrechnung
              .getGueltigeStimmenVorperiodeKumuliert(gueltige, uebergeordnetesGebiet, stimmenart)
              .minus(gueltigeStimmenVorperiode));
      if (prognose != null) {
        return prognose;
      }
    }

    return null;
  }

}
