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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.NlSystemGruppe;
import de.ivu.elect.business.internet.control.GebietUndStimmabgabeart;

public class NlErgebnisDatenGueltige extends AbstractErgebnisDaten {

  private static final NlSystemGruppe BLANKO = NlSystemGruppe.BLANKO;

  private final ErgebnisDatenGueltige ergebnisDatenGueltige;

  private final StimmenPool stimmen;

  private final StimmenKumulierer stimmenKumulierer;

  private final Optional<Gruppe> blankoGruppe;

  private final Map<GebietUndStimmabgabeart, Map<Stimmenart, Long>> blankoResult;

  public NlErgebnisDatenGueltige(NlErgebnisDaten nlErgebnisDaten) {
    super(nlErgebnisDaten.collectGebieteUntergeordnetFct(), nlErgebnisDaten.collectGebieteErfasstFct());

    this.ergebnisDatenGueltige = nlErgebnisDaten.getErgebnisDaten().getErgebnisDatenGueltige();

    this.stimmen = nlErgebnisDaten.getStimmen();
    this.stimmenKumulierer = nlErgebnisDaten.getStimmenKumulierer();

    this.blankoGruppe = nlErgebnisDaten.findSystemGruppe(BLANKO);
    this.blankoResult = new HashMap<>();
  }

  BestimmeStimmen<Stimmenart, GebietUndStimmabgabeart> blankoBestimmeStimmen = new BestimmeStimmen<Stimmenart, GebietUndStimmabgabeart>() {

    @Override
    public Long ermittleStimmen(Stimmenart stimmenart, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
      return blankoGruppe.map(gruppe -> stimmenKumulierer.getSummeFuerSystemGruppeAufGebietUndDarunter(gruppe, wahldurchfuehrungsgebiet, stimmen, stimmenart)).orElse(0L);
    }

    @Override
    public Map<Stimmenart, Long> getErgebnisUntergebiet(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
      return getSummeBlanko(gebietUndStimmabgabeart);
    }

    @Override
    public List<Stimmenart> getTargetAufGebiet(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
      return new ArrayList<>(BLANKO.getStimmenarten());
    }
  };

  public long getSummeGueltigeListenstimmen(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, Stimmabgabeart stimmabgabeart) {
    return getSummeGueltigeListenstimmen(new GebietUndStimmabgabeart(wahldurchfuehrungsgebiet, stimmabgabeart));
  }

  public long getSummeGueltigeListenstimmenNurGesamtGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeGueltigeListenstimmenNurUrnenwahlGemeinde(wahldurchfuehrungsgebiet) + getSummeGueltigeListenstimmenNurBriefwahlGemeinde(wahldurchfuehrungsgebiet);
  }

  public long getSummeGueltigeListenstimmenNurUrnenwahlGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeGueltigeListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurUrnenwahlGemeinde(wahldurchfuehrungsgebiet));
  }

  public long getSummeGueltigeListenstimmenNurBriefwahlGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeGueltigeListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurBriefwahlGemeinde(wahldurchfuehrungsgebiet));
  }

  public long getSummeGueltigeListenstimmenNurBriefwahlAusland(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeGueltigeListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurBriefwahlAusland(wahldurchfuehrungsgebiet));
  }

  public long getSummeGueltigeListenstimmen(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return notNull(ergebnisDatenGueltige.getZweitstimmenAktuellGueltig(gebietUndStimmabgabeart));
  }

  public long getSummeUngueltigeListenstimmen(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, Stimmabgabeart stimmabgabeart) {
    return getSummeUngueltigeListenstimmen(new GebietUndStimmabgabeart(wahldurchfuehrungsgebiet, stimmabgabeart));
  }

  public long getSummeUngueltigeListenstimmenNurGesamtGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeUngueltigeListenstimmenNurUrnenwahlGemeinde(wahldurchfuehrungsgebiet) + getSummeUngueltigeListenstimmenNurBriefwahlGemeinde(wahldurchfuehrungsgebiet);
  }

  public long getSummeUngueltigeListenstimmenNurUrnenwahlGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeUngueltigeListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurUrnenwahlGemeinde(wahldurchfuehrungsgebiet));
  }

  public long getSummeUngueltigeListenstimmenNurBriefwahlGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeUngueltigeListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurBriefwahlGemeinde(wahldurchfuehrungsgebiet));
  }

  public long getSummeUngueltigeListenstimmenNurBriefwahlAusland(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeUngueltigeListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurBriefwahlAusland(wahldurchfuehrungsgebiet));
  }

  public long getSummeUngueltigeListenstimmen(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return notNull(ergebnisDatenGueltige.getZweitstimmenAktuellUngueltig(gebietUndStimmabgabeart));
  }

  public long getSummeBlankoListenstimmen(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, Stimmabgabeart stimmabgabeart) {
    return getSummeBlankoListenstimmen(new GebietUndStimmabgabeart(wahldurchfuehrungsgebiet, stimmabgabeart));
  }

  public long getSummeBlankoListenstimmenNurGesamtGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeBlankoListenstimmenNurUrnenwahlGemeinde(wahldurchfuehrungsgebiet) + getSummeBlankoListenstimmenNurBriefwahlGemeinde(wahldurchfuehrungsgebiet);
  }

  public long getSummeBlankoListenstimmenNurUrnenwahlGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeBlankoListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurUrnenwahlGemeinde(wahldurchfuehrungsgebiet));
  }

  public long getSummeBlankoListenstimmenNurBriefwahlGemeinde(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeBlankoListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurBriefwahlGemeinde(wahldurchfuehrungsgebiet));
  }

  public long getSummeBlankoListenstimmenNurBriefwahlAusland(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return getSummeBlankoListenstimmen(NlErgebnisDaten.createGebietUndStimmabgabeartNurBriefwahlAusland(wahldurchfuehrungsgebiet));
  }

  public long getSummeBlankoListenstimmen(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeBlanko(gebietUndStimmabgabeart, Stimmenart.LISTENSTIMME_LEER);
  }

  private long getSummeBlanko(GebietUndStimmabgabeart gebietUndStimmabgabeart, Stimmenart stimmenart) {
    return notNull(getSummeBlanko(gebietUndStimmabgabeart).get(stimmenart));
  }

  private Map<Stimmenart, Long> getSummeBlanko(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return bestimmeStimmenOderSummiereAufUntergebieten(gebietUndStimmabgabeart, blankoResult, blankoBestimmeStimmen);
  }
}
