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

import de.ivu.elect.business.gebietsbaum.boundary.AbstractWahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietTK;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.UmgangHinterlegteAWerte;
import de.ivu.elect.business.wahl.entity.Wahl;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/*
 * Weil das Gott-Objekt ErgebnisDaten vom Ergebnis abhängt, hier ein schlankes Objekt nur für die A-Werte.
 */
public class AWerteAktualisierer extends AbstractAWerteAktualisierer<Wahldurchfuehrungsgebiet>{

  private final Wahl wahl;
  private final AbstractWahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;
  private final UmgangHinterlegteAWerte umgangHinterlegteAWerte;

  Map<GebietTK, Wahldurchfuehrungsgebiet> wahldurchfuehrungsgebietZuTKMap;
  Map<Wahldurchfuehrungsgebiet, Long> anzahlWahlberechtigteOhneWahlscheinPerErfassungsgebiet;
  Map<Wahldurchfuehrungsgebiet, Long> anzahlWahlberechtigteMitWahlscheinPerErfassungsgebiet;
  Map<Wahldurchfuehrungsgebiet, Long> anzahlWahlberechtigteNichtImWaehlerverzeichnisPerErfassungsgebiet;

  public AWerteAktualisierer(Wahl wahl, AbstractWahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO, UmgangHinterlegteAWerte umgangHinterlegteAWerte) {
    this.wahl = wahl;
    this.wahldurchfuehrungsgebietDAO = wahldurchfuehrungsgebietDAO;
    this.umgangHinterlegteAWerte = umgangHinterlegteAWerte;
  }

  public void aktualisiereAWerteFuerUebergeordneteGebieteVon(@Nullable Wahldurchfuehrungsgebiet erfassungsgebiet) {

    if (erfassungsgebiet == null || !umgangHinterlegteAWerte.isAktualisiereAWerteFuerUebergeordneteGebiete()) {
      return;
    }

    initialisiereMapsIfNotInitialisiert();

    Wahldurchfuehrungsgebiet erfassungsgebietInitialisert = wahldurchfuehrungsgebietZuTKMap.get(erfassungsgebiet.getGebietTK());

    if (erfassungsgebietInitialisert == null) {
      wahldurchfuehrungsgebietZuTKMap.put(erfassungsgebiet.getWahldurchfuehrungsgebietTK(), erfassungsgebiet);
      erfassungsgebietInitialisert = erfassungsgebiet;
      // throw new IllegalStateException("Wahldurchführungsgebiet fehlt in Initialisierung: " + erfassungsgebiet.getGebietTK());
    }

    anzahlWahlberechtigteOhneWahlscheinPerErfassungsgebiet.put(erfassungsgebietInitialisert, erfassungsgebiet.getAnzahlWahlberechtigteOhneWahlschein());
    anzahlWahlberechtigteMitWahlscheinPerErfassungsgebiet.put(erfassungsgebietInitialisert, erfassungsgebiet.getAnzahlWahlberechtigteMitWahlschein());
    anzahlWahlberechtigteNichtImWaehlerverzeichnisPerErfassungsgebiet.put(erfassungsgebietInitialisert, erfassungsgebiet.getAnzahlWahlberechtigteNichtImWaehlerverzeichnis());

    Gebiet uebergeordnetesGebiet = erfassungsgebietInitialisert.getUebergeordnetesGebiet();

    while (uebergeordnetesGebiet != null) {
      Wahldurchfuehrungsgebiet uebergeordnetesWahldurchfuehrungsgebiet = wahldurchfuehrungsgebietZuTKMap.get(uebergeordnetesGebiet.getGebietTK());

      if (uebergeordnetesWahldurchfuehrungsgebiet == null) {
        throw new IllegalStateException("Wahldurchführungsgebiet fehlt in Initialisierung: " + erfassungsgebiet.getGebietTK());
      }

      uebergeordnetesWahldurchfuehrungsgebiet
          .setAnzahlWahlberechtigteOhneWahlschein(getAWertKumuliert(uebergeordnetesWahldurchfuehrungsgebiet, anzahlWahlberechtigteOhneWahlscheinPerErfassungsgebiet));
      uebergeordnetesWahldurchfuehrungsgebiet.setAnzahlWahlberechtigteMitWahlschein(getAWertKumuliert(uebergeordnetesWahldurchfuehrungsgebiet, anzahlWahlberechtigteMitWahlscheinPerErfassungsgebiet));
      uebergeordnetesWahldurchfuehrungsgebiet
          .setAnzahlWahlberechtigteNichtImWaehlerverzeichnis(getAWertKumuliert(uebergeordnetesWahldurchfuehrungsgebiet, anzahlWahlberechtigteNichtImWaehlerverzeichnisPerErfassungsgebiet));
      uebergeordnetesGebiet = uebergeordnetesGebiet.getUebergeordnetesGebiet();
    }
  }


  void initialisiereMapsIfNotInitialisiert() {
    if (wahldurchfuehrungsgebietZuTKMap == null) {
      List<Wahldurchfuehrungsgebiet> wahldurchfuehrungsgebiete = wahldurchfuehrungsgebietDAO.findByWahl(wahl);

      wahldurchfuehrungsgebietZuTKMap = GebietTK.mappeGebietNachTK(wahldurchfuehrungsgebiete);
      anzahlWahlberechtigteOhneWahlscheinPerErfassungsgebiet = new HashMap<>();
      anzahlWahlberechtigteMitWahlscheinPerErfassungsgebiet = new HashMap<>();
      anzahlWahlberechtigteNichtImWaehlerverzeichnisPerErfassungsgebiet = new HashMap<>();

      for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : wahldurchfuehrungsgebiete) {
        if (wahldurchfuehrungsgebiet.isErfassungsgebiet()) {
          if (wahldurchfuehrungsgebiet.hasAnzahlWahlberechtigteOhneWahlschein()) {
            anzahlWahlberechtigteOhneWahlscheinPerErfassungsgebiet.put(wahldurchfuehrungsgebiet, wahldurchfuehrungsgebiet.getAnzahlWahlberechtigteOhneWahlschein());
          }

          if (wahldurchfuehrungsgebiet.hasAnzahlWahlberechtigteMitWahlschein()) {
            anzahlWahlberechtigteMitWahlscheinPerErfassungsgebiet.put(wahldurchfuehrungsgebiet, wahldurchfuehrungsgebiet.getAnzahlWahlberechtigteMitWahlschein());
          }

          if (wahldurchfuehrungsgebiet.hasAnzahlWahlberechtigteNichtImWaehlerverzeichnis()) {
            anzahlWahlberechtigteNichtImWaehlerverzeichnisPerErfassungsgebiet.put(wahldurchfuehrungsgebiet, wahldurchfuehrungsgebiet.getAnzahlWahlberechtigteNichtImWaehlerverzeichnis());
          }
        }
      }
    }
  }

  @Override
  protected boolean isErfassungsgebiet(Wahldurchfuehrungsgebiet gebiet) {
    return gebiet.isErfassungsgebiet();
  }

  @Override
  public boolean isAWerteAktualisieren(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return wahldurchfuehrungsgebiet.hasChangedAnzahlWahlberechtigteOhneWahlschein() || wahldurchfuehrungsgebiet.hasChangedAnzahlWahlberechtigteMitWahlschein()
        || wahldurchfuehrungsgebiet.hasChangedAnzahlWahlberechtigteNichtImWaehlerverzeichnis();
  }

  @Override
  public void aWerteZuruecksetzen(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    wahldurchfuehrungsgebiet.setAnzahlWahlberechtigteOhneWahlschein(null);
    wahldurchfuehrungsgebiet.setAnzahlWahlberechtigteMitWahlschein(null);
    wahldurchfuehrungsgebiet.setAnzahlWahlberechtigteNichtImWaehlerverzeichnis(null);
  }

}
