
package de.ivu.elect.business.stimmeingabe.entity;

import static java.util.stream.Collectors.toList;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;

public class StimmeingabeKopfzahlErfassenModel extends AbstractStimmenErfassenModel {

  private final Ergebniseingang ergebniseingang;

  private final Map<Stimmenart, StimmeingabeKopfzahl> stimmeingabenKopfzahlWahlberechtigte;

  private final Map<Stimmenart, StimmeingabeKopfzahl> stimmeingabenKopfzahlWaehler;

  private final Map<Stimmenart, StimmeingabeKopfzahl> stimmeingabenKopfzahlUebrige;

  public StimmeingabeKopfzahlErfassenModel(Wahldurchfuehrungsgebiet bezugGebiet, Ergebniseingang ergebniseingang) {
    super(bezugGebiet);

    this.ergebniseingang = ergebniseingang;

    this.stimmeingabenKopfzahlWahlberechtigte = new ConcurrentHashMap<>();
    this.stimmeingabenKopfzahlWaehler = new ConcurrentHashMap<>();
    this.stimmeingabenKopfzahlUebrige = new ConcurrentHashMap<>();
  }

  public Wahlart getWahlart() {
    return getWahldurchfuehrung().getWahlart();
  }

  public Wahldurchfuehrung getWahldurchfuehrung() {
    return getBezugGebiet().getWahldurchfuehrung();
  }

  public Ergebniseingangsart getErgebniseingangsart() {
    return getErgebniseingang().getErgebniseingangsart();
  }

  public Ergebniseingang getErgebniseingang() {
    return ergebniseingang;
  }

  public boolean isBriefwahlgebiet() {
    return getBezugGebiet().isBriefwahlgebiet();
  }

  public boolean hasPruefkennzeichenWahlberechtigte() {
    return getPruefkennzeichenWahlberechtigte() != null;
  }

  public StimmeingabeKopfzahl getPruefkennzeichenWahlberechtigte() {
    return getStimmeingabeKopfzahlWahlberechtigte(Stimmenart.PRUEFKENNZEICHEN);
  }

  public void setPruefkennzeichenWahlberechtigte(StimmeingabeKopfzahl pruefkennzeichenWahlberechtigte) {
    setStimmeingabeKopfzahlWahlberechtigte(Stimmenart.PRUEFKENNZEICHEN, pruefkennzeichenWahlberechtigte);
  }

  public Optional<Stimmeingabe> getPruefkennzeichenWahlberechtigteStimmeingabe() {
    if (hasPruefkennzeichenWahlberechtigte()) {
      return Optional.ofNullable(getPruefkennzeichenWahlberechtigte().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWahlberechtigteOhneWahlschein() {
    return getWahlberechtigteOhneWahlschein() != null;
  }

  public StimmeingabeKopfzahl getWahlberechtigteOhneWahlschein() {
    return getStimmeingabeKopfzahlWahlberechtigte(Stimmenart.OHNE_WAHLSCHEIN);
  }

  public void setWahlberechtigteOhneWahlschein(StimmeingabeKopfzahl wahlberechtigteOhneWahlschein) {
    setStimmeingabeKopfzahlWahlberechtigte(Stimmenart.OHNE_WAHLSCHEIN, wahlberechtigteOhneWahlschein);
  }

  public Optional<Stimmeingabe> getWahlberechtigteOhneWahlscheinStimmeingabe() {
    if (hasWahlberechtigteOhneWahlschein()) {
      return Optional.ofNullable(getWahlberechtigteOhneWahlschein().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWahlberechtigteMitWahlschein() {
    return getWahlberechtigteMitWahlschein() != null;
  }

  public StimmeingabeKopfzahl getWahlberechtigteMitWahlschein() {
    return getStimmeingabeKopfzahlWahlberechtigte(Stimmenart.MIT_WAHLSCHEIN);
  }

  public void setWahlberechtigteMitWahlschein(StimmeingabeKopfzahl wahlberechtigteMitWahlschein) {
    setStimmeingabeKopfzahlWahlberechtigte(Stimmenart.MIT_WAHLSCHEIN, wahlberechtigteMitWahlschein);
  }

  public Optional<Stimmeingabe> getWahlberechtigteMitWahlscheinStimmeingabe() {
    if (hasWahlberechtigteMitWahlschein()) {
      return Optional.ofNullable(getWahlberechtigteMitWahlschein().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWahlberechtigteNichtImWaehlerverzeichnis() {
    return getWahlberechtigteNichtImWaehlerverzeichnis() != null;
  }

  public StimmeingabeKopfzahl getWahlberechtigteNichtImWaehlerverzeichnis() {
    return getStimmeingabeKopfzahlWahlberechtigte(Stimmenart.NICHT_IM_WAEHLERVERZEICHNIS);
  }

  public void setWahlberechtigteNichtImWaehlerverzeichnis(StimmeingabeKopfzahl wahlberechtigteNichtImWaehlerverzeichnis) {
    setStimmeingabeKopfzahlWahlberechtigte(Stimmenart.NICHT_IM_WAEHLERVERZEICHNIS, wahlberechtigteNichtImWaehlerverzeichnis);
  }

  public Optional<Stimmeingabe> getWahlberechtigteNichtImWaehlerverzeichnisStimmeingabe() {
    if (hasWahlberechtigteNichtImWaehlerverzeichnis()) {
      return Optional.ofNullable(getWahlberechtigteNichtImWaehlerverzeichnis().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWahlberechtigteGesamt() {
    return getWahlberechtigteGesamt() != null;
  }

  public StimmeingabeKopfzahl getWahlberechtigteGesamt() {
    return getStimmeingabeKopfzahlWahlberechtigte(Stimmenart.GESAMT);
  }

  public void setWahlberechtigteGesamt(StimmeingabeKopfzahl wahlberechtigteGesamt) {
    setStimmeingabeKopfzahlWahlberechtigte(Stimmenart.GESAMT, wahlberechtigteGesamt);
  }

  public Optional<Stimmeingabe> getWahlberechtigteGesamtStimmeingabe() {
    if (hasWahlberechtigteGesamt()) {
      return Optional.ofNullable(getWahlberechtigteGesamt().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWaehlerOhneWahlschein() {
    return getWaehlerOhneWahlschein() != null;
  }

  public StimmeingabeKopfzahl getWaehlerOhneWahlschein() {
    return getStimmeingabeKopfzahlWaehler(Stimmenart.OHNE_WAHLSCHEIN);
  }

  public void setWaehlerOhneWahlschein(StimmeingabeKopfzahl waehlerOhneWahlschein) {
    setStimmeingabeKopfzahlWaehler(Stimmenart.OHNE_WAHLSCHEIN, waehlerOhneWahlschein);
  }

  public Optional<Stimmeingabe> getWaehlerOhneWahlscheinStimmeingabe() {
    if (hasWaehlerOhneWahlschein()) {
      return Optional.ofNullable(getWaehlerOhneWahlschein().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWaehlerMitWahlschein() {
    return getWaehlerMitWahlschein() != null;
  }

  public StimmeingabeKopfzahl getWaehlerMitWahlschein() {
    return getStimmeingabeKopfzahlWaehler(Stimmenart.MIT_WAHLSCHEIN);
  }

  public void setWaehlerMitWahlschein(StimmeingabeKopfzahl waehlerMitWahlschein) {
    setStimmeingabeKopfzahlWaehler(Stimmenart.MIT_WAHLSCHEIN, waehlerMitWahlschein);
  }

  public Optional<Stimmeingabe> getWaehlerMitWahlscheinStimmeingabe() {
    if (hasWaehlerMitWahlschein()) {
      return Optional.ofNullable(getWaehlerMitWahlschein().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl() {
    return getWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl() != null;
  }

  public StimmeingabeKopfzahl getWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl() {
    return getStimmeingabeKopfzahlWaehler(Stimmenart.ALS_URNENWAHL_IN_URNE);
  }

  public void setWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl(StimmeingabeKopfzahl waehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl) {
    setStimmeingabeKopfzahlWaehler(Stimmenart.ALS_URNENWAHL_IN_URNE, waehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl);
  }

  public Optional<Stimmeingabe> getWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahlStimmeingabe() {
    if (hasWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl()) {
      return Optional.ofNullable(getWaehlerMitWahlscheinInUrnenwahlAnzahlAusUrnenwahl().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl() {
    return getWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl() != null;
  }

  public StimmeingabeKopfzahl getWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl() {
    return getStimmeingabeKopfzahlWaehler(Stimmenart.ALS_BRIEFWAHL_IN_URNE);
  }

  public void setWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl(StimmeingabeKopfzahl waehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl) {
    setStimmeingabeKopfzahlWaehler(Stimmenart.ALS_BRIEFWAHL_IN_URNE, waehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl);
  }

  public Optional<Stimmeingabe> getWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahlStimmeingabe() {
    if (hasWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl()) {
      return Optional.ofNullable(getWaehlerMitWahlscheinInUrnenwahlAnzahlAusBriefwahl().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWaehlerMitVollmacht() {
    return getWaehlerMitVollmacht() != null;
  }

  public StimmeingabeKopfzahl getWaehlerMitVollmacht() {
    return getStimmeingabeKopfzahlWaehler(Stimmenart.MIT_VOLLMACHT);
  }

  public void setWaehlerMitVollmacht(StimmeingabeKopfzahl waehlerMitVollmacht) {
    setStimmeingabeKopfzahlWaehler(Stimmenart.MIT_VOLLMACHT, waehlerMitVollmacht);
  }

  public Optional<Stimmeingabe> getWaehlerMitVollmachtStimmeingabe() {
    if (hasWaehlerMitVollmacht()) {
      return Optional.ofNullable(getWaehlerMitVollmacht().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasWaehlerGesamt() {
    return getWaehlerGesamt() != null;
  }

  public StimmeingabeKopfzahl getWaehlerGesamt() {
    return getStimmeingabeKopfzahlWaehler(Stimmenart.GESAMT);
  }

  public void setWaehlerGesamt(StimmeingabeKopfzahl waehlerGesamt) {
    setStimmeingabeKopfzahlWaehler(Stimmenart.GESAMT, waehlerGesamt);
  }

  public Optional<Stimmeingabe> getWaehlerGesamtStimmeingabe() {
    if (hasWaehlerGesamt()) {
      return Optional.ofNullable(getWaehlerGesamt().getStimmeingabe());
    }

    return Optional.empty();
  }

  protected StimmeingabeKopfzahl getStimmeingabeKopfzahlWahlberechtigte(Stimmenart stimmenart) {
    return getStimmeingabeKopfzahl(stimmeingabenKopfzahlWahlberechtigte, stimmenart);
  }

  protected void setStimmeingabeKopfzahlWahlberechtigte(Stimmenart stimmenart, StimmeingabeKopfzahl stimmeingabeKopfzahl) {
    setStimmeingabeKopfzahl(stimmeingabenKopfzahlWahlberechtigte, stimmenart, stimmeingabeKopfzahl);
  }

  protected StimmeingabeKopfzahl getStimmeingabeKopfzahlWaehler(Stimmenart stimmenart) {
    return getStimmeingabeKopfzahl(stimmeingabenKopfzahlWaehler, stimmenart);
  }

  protected void setStimmeingabeKopfzahlWaehler(Stimmenart stimmenart, StimmeingabeKopfzahl stimmeingabeKopfzahl) {
    setStimmeingabeKopfzahl(stimmeingabenKopfzahlWaehler, stimmenart, stimmeingabeKopfzahl);
  }

  protected StimmeingabeKopfzahl getStimmeingabeKopfzahlUebrige(Stimmenart stimmenart) {
    return getStimmeingabeKopfzahl(stimmeingabenKopfzahlUebrige, stimmenart);
  }

  protected void setStimmeingabeKopfzahlUebrige(Stimmenart stimmenart, StimmeingabeKopfzahl stimmeingabeKopfzahl) {
    setStimmeingabeKopfzahl(stimmeingabenKopfzahlUebrige, stimmenart, stimmeingabeKopfzahl);
  }

  private StimmeingabeKopfzahl getStimmeingabeKopfzahl(Map<Stimmenart, StimmeingabeKopfzahl> stimmeingabenKopfzahl, Stimmenart stimmenart) {
    return stimmeingabenKopfzahl.get(stimmenart);
  }

  private void setStimmeingabeKopfzahl(Map<Stimmenart, StimmeingabeKopfzahl> stimmeingabenKopfzahl, Stimmenart stimmenart, StimmeingabeKopfzahl stimmeingabeKopfzahl) {
    if (stimmeingabeKopfzahl == null) {
      stimmeingabenKopfzahl.remove(stimmenart);
    } else {
      stimmeingabenKopfzahl.put(stimmenart, stimmeingabeKopfzahl);
    }
  }

  @Override
  public Collection<StimmeingabeKopfzahl> getAllStimmeingabeValueObjects() {
    Collection<StimmeingabeKopfzahl> result = new HashSet<>();
    result.addAll(stimmeingabenKopfzahlWahlberechtigte.values());
    result.addAll(stimmeingabenKopfzahlWaehler.values());
    result.addAll(stimmeingabenKopfzahlUebrige.values());

    return result.stream().filter(Objects::nonNull).collect(toList());
  }
}
