
package de.ivu.elect.business.stimmeingabe.control.fiktive;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gruppe.entity.SystemGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppeEigenschaften;
import de.ivu.elect.business.hochrechnung.entity.AnzahlStimmenProWaehlerNachStimmenartBestimmer;
import de.ivu.elect.business.hochrechnung.entity.GebietDaten;
import de.ivu.elect.business.hochrechnung.entity.StimmenhochrechnerGebietAusgabedaten;
import de.ivu.elect.business.hochrechnung.entity.WahlteilnehmerAnzahl;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;

public class WahlberechtigteUndWaehlerStimmeingabenAusFiktivwertenSetzer extends AbstractStimmeingabenAusFiktivwertenSetzer {

  private static final Logger LOG = LoggerFactory.getLogger(WahlberechtigteUndWaehlerStimmeingabenAusFiktivwertenSetzer.class);

  @Inject
  private transient SystemGruppeEigenschaften systemGruppeEigenschaften;

  public WahlberechtigteUndWaehlerStimmeingabenAusFiktivwertenSetzer() {
    super();
  }

  @Override
  public boolean isVomLetztenErgebniseingangUebernommeneStimmenZuUeberschreiben(Ergebniseingang ergebniseingangAktuell, Collection<Stimmeingabe> uebernommeneStimmeingaben) {
    if (ergebniseingangAktuell.isErgebniseingangsartVorlaeufig()) {
      return true; // Vorlaeufiger Ergebniseingang kann ueberschrieben werden
    }

    // ueberschreibe, wenn es dann keine echt positive Zahlen vorhanden sind.
    return uebernommeneStimmeingaben.stream().noneMatch(stimmeingabe -> stimmeingabe != null && stimmeingabe.hasAnzahlGroesserNull());
  }

  @Override
  public void setzeErgebniseingangStimmeingabenAnzahlAusHochgerechnetenWerten(Ergebniseingang ergebniseingang, StimmenhochrechnerGebietAusgabedaten hochrechnerAusgabedaten, AnzahlStimmenProWaehlerNachStimmenartBestimmer anzahlStimmenProWaehlerBestimmer) {

    GebietDaten<Double> hochgerechnetAnteile = hochrechnerAusgabedaten.getHochgerechnetAnteile();
    if (hochgerechnetAnteile == null) {
      return;
    }

    Map<SystemGruppe, Map<Stimmenart, Stimmeingabe>> stimmeingabenPerStimmenartUndSystemGruppe = findStimmeingabenPerStimmenartUndSystemGruppe(ergebniseingang);

    Map<Stimmenart, Stimmeingabe> wahlberechtigteStimmeingaben = stimmeingabenPerStimmenartUndSystemGruppe.get(SystemGruppe.WAHLBERECHTIGTE);
    if (wahlberechtigteStimmeingaben == null) {
      // ist insb. bei Briefwahlbezirken leer, weil hier A-Werte nicht erfasst werden
      wahlberechtigteStimmeingaben = Collections.emptyMap();
    }

    fuehleWahlteilnehmerAnzahlWennUeberschreibbar(ergebniseingang, hochgerechnetAnteile.getAnzahlWahlberechtigteImGebiet(), wahlberechtigteStimmeingaben);

    Map<Stimmenart, Stimmeingabe> waehlerStimmeingaben = stimmeingabenPerStimmenartUndSystemGruppe.get(SystemGruppe.WAEHLER);
    fuehleWahlteilnehmerAnzahlWennUeberschreibbar(ergebniseingang, hochgerechnetAnteile.getAnzahlWaehlerImGebiet(), waehlerStimmeingaben);
  }

  private void fuehleWahlteilnehmerAnzahlWennUeberschreibbar(Ergebniseingang ergebniseingang, WahlteilnehmerAnzahl wahlteilnehmerAnzahl, Map<Stimmenart, Stimmeingabe> wahlteilnehmerStimmeingaben) {
    if (wahlteilnehmerAnzahl == null) {
      return;
    }
    if (isVomLetztenErgebniseingangUebernommeneStimmenZuUeberschreiben(ergebniseingang, wahlteilnehmerStimmeingaben.values())) {
      wahlteilnehmerStimmeingaben
          .forEach(((stimmenart, stimmeingabe) -> setzeStimmenEingabeAnzahl(getWahlteilnehmerAnzahl(wahlteilnehmerAnzahl, stimmenart), stimmeingabe)));
    }
  }

  private Long getWahlteilnehmerAnzahl(WahlteilnehmerAnzahl wahlteilnehmerAnzahl, Stimmenart stimmenart) {
    return stimmenart.isGesamt()? wahlteilnehmerAnzahl.getGesamtNotNull(): wahlteilnehmerAnzahl.getAnzahl(stimmenart);
  }

  public boolean hasAnzahlenWahlberechtigteFuerFiktiveWerte(Ergebniseingang ergebniseingang) {
    return ergebniseingang != null && ergebniseingang.getWahldurchfuehrungsgebiet() != null && ergebniseingang.getWahldurchfuehrungsgebiet().hasAnyAnzahlWahlberechtigteGroesserNull();
  }

  private Map<SystemGruppe, Map<Stimmenart, Stimmeingabe>> findStimmeingabenPerStimmenartUndSystemGruppe(Ergebniseingang ergebniseingang) {
    Map<SystemGruppe, Map<Stimmenart, Stimmeingabe>> result = new HashMap<>();

    for (Stimmeingabe stimmeingabe : ergebniseingang.getStimmeingaben()) {
      if (stimmeingabe.isSystemGruppenStimmeingabe()) {

        SystemGruppe systemGruppe = stimmeingabe.getGruppe().getSystemGruppe(getSystemGruppeEigenschaften());
        Map<Stimmenart, Stimmeingabe> stimmeingabenPerStimmenart = result.get(systemGruppe);
        if (stimmeingabenPerStimmenart == null) {
          stimmeingabenPerStimmenart = new HashMap<>();
          result.put(systemGruppe, stimmeingabenPerStimmenart);
        }

        stimmeingabenPerStimmenart.put(stimmeingabe.getStimmenart(), stimmeingabe);

      }
    }

    return result;
  }

  protected SystemGruppeEigenschaften getSystemGruppeEigenschaften() {
    return systemGruppeEigenschaften;
  }

  private static void log(String message, Object... args) {
    // HINT: Einrückung, damit Ausgaben zu StimmeingabeFiktivwerteCreate passen
    LOG.debug("\t\t" + message, args);
  }

}
