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

import static java.util.Arrays.asList;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;

import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
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.internet.control.GebietUndStimmabgabeart;

public class ErgebnisDatenWaehler extends AbstractErgebnisDaten {

  private final Map<GebietUndStimmabgabeart, Map<Stimmenart, Long>> waehler = new HashMap<>();

  private final StimmenPool stimmen;

  private final StimmenKumulierer stimmenKumulierer;

  public ErgebnisDatenWaehler(Function<Wahldurchfuehrungsgebiet, List<Wahldurchfuehrungsgebiet>> untergeordneteGebiete, StimmenPool stimmen, StimmenKumulierer stimmenKumulierer,
      Supplier<Set<Gebiet>> erfassteGebiete) {
    super(untergeordneteGebiete, erfassteGebiete);

    this.stimmen = stimmen;
    this.stimmenKumulierer = stimmenKumulierer;
  }

  private StimmenPool getStimmen() {
    return stimmen;
  }

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

    @Override
    public Long ermittleStimmen(Stimmenart stimmenart, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
      return stimmenKumulierer.getSummeWaehlerStimmenAufGebiet(getStimmen(), wahldurchfuehrungsgebiet, stimmenart);
    }

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

    @Override
    public List<Stimmenart> getTargetAufGebiet(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
      return asList(Stimmenart.OHNE_WAHLSCHEIN, Stimmenart.MIT_WAHLSCHEIN, Stimmenart.ALS_URNENWAHL_IN_URNE, Stimmenart.ALS_BRIEFWAHL_IN_URNE, Stimmenart.MIT_VOLLMACHT, Stimmenart.GESAMT);
    }
  };

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

  public long getSummeWaehlerOhneWahlschein(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeWaehler(gebietUndStimmabgabeart, Stimmenart.OHNE_WAHLSCHEIN);
  }

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

  public long getSummeWaehlerMitWahlschein(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeWaehler(gebietUndStimmabgabeart, Stimmenart.MIT_WAHLSCHEIN);
  }

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

  public long getSummeWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahl(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeWaehler(gebietUndStimmabgabeart, Stimmenart.ALS_URNENWAHL_IN_URNE);
  }

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

  public long getSummeWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahl(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeWaehler(gebietUndStimmabgabeart, Stimmenart.ALS_BRIEFWAHL_IN_URNE);
  }

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

  public long getSummeWaehlerMitVollmacht(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeWaehler(gebietUndStimmabgabeart, Stimmenart.MIT_VOLLMACHT);
  }

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

  public long getSummeWaehlerGesamt(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return getSummeWaehler(gebietUndStimmabgabeart, Stimmenart.GESAMT);
  }

  public long getSummeWaehler(GebietUndStimmabgabeart gebietUndStimmabgabeart, Stimmenart stimmenart) {
    return notNull(getSummeWaehler(gebietUndStimmabgabeart).get(stimmenart));
  }

  private Map<Stimmenart, Long> getSummeWaehler(GebietUndStimmabgabeart gebietUndStimmabgabeart) {
    return bestimmeStimmenOderSummiereAufUntergebieten(gebietUndStimmabgabeart, waehler, waehlerBestimmeStimmen);
  }
}
