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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.NlSystemGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppe;

public class NlStimmeingabeKopfzahlErfassenModel extends StimmeingabeKopfzahlErfassenModel {

  private static final NlSystemGruppe STIMMZETTEL_EINGENOMMEN = NlSystemGruppe.STIMMZETTEL_EINGENOMMEN;

  private static final NlSystemGruppe STIMMZETTEL_EINGENOMMEN_ABWEICHEND = NlSystemGruppe.STIMMZETTEL_EINGENOMMEN_ABWEICHEND;

  public NlStimmeingabeKopfzahlErfassenModel(Wahldurchfuehrungsgebiet bezugGebiet, Ergebniseingang ergebniseingang) {
    super(bezugGebiet, ergebniseingang);
  }

  public Collection<Stimmeingabe> getWaehlerGesamtStimmeingaben() {
    Collection<Stimmeingabe> result = new ArrayList<>();

    Optional<Stimmeingabe> stimmeingabeWaehlerGesamt = getWaehlerGesamtStimmeingabe();

    if (stimmeingabeWaehlerGesamt.isPresent()) {
      result.add(stimmeingabeWaehlerGesamt.get());
    } else {
      Optional<Stimmeingabe> stimmeingabeWaehlerOhneWahlschein = getWaehlerOhneWahlscheinStimmeingabe();
      Optional<Stimmeingabe> stimmeingabeWaehlerMitWahlschein = getWaehlerMitWahlscheinStimmeingabe();

      if (stimmeingabeWaehlerOhneWahlschein.isPresent() && stimmeingabeWaehlerMitWahlschein.isPresent()) { // ELECT-10068
        stimmeingabeWaehlerOhneWahlschein.ifPresent(result::add);
        stimmeingabeWaehlerMitWahlschein.ifPresent(result::add);
        getWaehlerMitVollmachtStimmeingabe().ifPresent(result::add);
      }
    }

    return result;
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenGesamtStimmeingabe() {
    if (hasStimmzettelEingenommenGesamt()) {
      return Optional.ofNullable(getStimmzettelEingenommenGesamt().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenGesamt() {
    return getStimmzettelEingenommenGesamt() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenGesamt() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN, Stimmenart.GESAMT_EINGENOMMEN);
  }

  public Collection<Stimmeingabe> getStimmzettelEingenommenAbweichendStimmeingaben() {
    Collection<Stimmeingabe> result = new ArrayList<>();

    getStimmzettelEingenommenAbweichendZuwenigStimmeingabe().ifPresent(result::add);
    getStimmzettelEingenommenAbweichendZuvielStimmeingabe().ifPresent(result::add);

    result.addAll(getStimmzettelEingenommenAbweichendGrundStimmeingaben());

    return result;
  }

  public Collection<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundStimmeingaben() {
    Collection<Stimmeingabe> result = new ArrayList<>();

    getStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegebenStimmeingabe().ifPresent(result::add);
    getStimmzettelEingenommenAbweichendGrundAusgegebenZuwenigStimmeingabe().ifPresent(result::add);
    getStimmzettelEingenommenAbweichendGrundAusgegebenZuvielStimmeingabe().ifPresent(result::add);

    getStimmzettelEingenommenAbweichendGrundVerlorenStimmeingabe().ifPresent(result::add);

    getStimmzettelEingenommenAbweichendGrundUnbekanntStimmeingabe().ifPresent(result::add);
    getStimmzettelEingenommenAbweichendGrundSonstigesStimmeingabe().ifPresent(result::add);

    return result;
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendZuwenigStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendZuwenig()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendZuwenig().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendZuwenig() {
    return getStimmzettelEingenommenAbweichendZuwenig() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendZuwenig() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_ZUWENIG);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendZuvielStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendZuviel()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendZuviel().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendZuviel() {
    return getStimmzettelEingenommenAbweichendZuviel() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendZuviel() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_ZUVIEL);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegebenStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben() {
    return getStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundAusgegebenNichtAbgegeben() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_AUSGEGEBEN_NICHT_ABGEGEBEN);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundAusgegebenZuwenigStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig() {
    return getStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundAusgegebenZuwenig() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_AUSGEGEBEN_ZUWENIG);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundAusgegebenZuvielStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundAusgegebenZuviel()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundAusgegebenZuviel().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundAusgegebenZuviel() {
    return getStimmzettelEingenommenAbweichendGrundAusgegebenZuviel() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundAusgegebenZuviel() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_AUSGEGEBEN_ZUVIEL);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenigStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig() {
    return getStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundInWahlbriefZuwenig() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_IN_WAHLBRIEF_ZUWENIG);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundInWahlbriefZuvielStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel() {
    return getStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundInWahlbriefZuviel() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_IN_WAHLBRIEF_ZUVIEL);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundVerlorenStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundVerloren()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundVerloren().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundVerloren() {
    return getStimmzettelEingenommenAbweichendGrundVerloren() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundVerloren() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_VERLOREN);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundUnbekanntStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundUnbekannt()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundUnbekannt().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundUnbekannt() {
    return getStimmzettelEingenommenAbweichendGrundUnbekannt() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundUnbekannt() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_UNBEKANNT);
  }

  public Optional<Stimmeingabe> getStimmzettelEingenommenAbweichendGrundSonstigesStimmeingabe() {
    if (hasStimmzettelEingenommenAbweichendGrundSonstiges()) {
      return Optional.ofNullable(getStimmzettelEingenommenAbweichendGrundSonstiges().getStimmeingabe());
    }

    return Optional.empty();
  }

  public boolean hasStimmzettelEingenommenAbweichendGrundSonstiges() {
    return getStimmzettelEingenommenAbweichendGrundSonstiges() != null;
  }

  public StimmeingabeKopfzahl getStimmzettelEingenommenAbweichendGrundSonstiges() {
    return getStimmeingabeKopfzahl(STIMMZETTEL_EINGENOMMEN_ABWEICHEND, Stimmenart.GESAMT_ABWEICHEND_GRUND_SONSTIGES);
  }

  public boolean hasStimmeingabeKopfzahl(NlSystemGruppe nlSystemGruppe, Stimmenart stimmenart) {
    return getStimmeingabeKopfzahl(nlSystemGruppe, stimmenart) != null;
  }

  public StimmeingabeKopfzahl getStimmeingabeKopfzahl(NlSystemGruppe nlSystemGruppe, Stimmenart stimmenart) {
    SystemGruppe systemGruppe = nlSystemGruppe.getSystemGruppe();

    if (SystemGruppe.WAHLBERECHTIGTE.equals(systemGruppe)) {
      return getStimmeingabeKopfzahlWahlberechtigte(stimmenart);
    }

    if (SystemGruppe.WAEHLER.equals(systemGruppe)) {
      return getStimmeingabeKopfzahlWaehler(stimmenart);
    }

    if (SystemGruppe.UEBRIGE.equals(systemGruppe)) {
      return getStimmeingabeKopfzahlUebrige(stimmenart);
    }

    return null;
  }

  public void setStimmeingabeKopfzahl(NlSystemGruppe nlSystemGruppe, Stimmenart stimmenart, StimmeingabeKopfzahl stimmeingabeKopfzahl) {
    SystemGruppe systemGruppe = nlSystemGruppe.getSystemGruppe();

    if (!nlSystemGruppe.getStimmenarten().contains(stimmenart)) {
      throw new IllegalArgumentException("Stimmenart NICHT unterstuetzt [nlSystemGruppe = " + nlSystemGruppe + ", systemGruppe = " + systemGruppe + ", stimmenart = " + stimmenart + "]");
    }

    if (SystemGruppe.WAHLBERECHTIGTE.equals(systemGruppe)) {
      setStimmeingabeKopfzahlWahlberechtigte(stimmenart, stimmeingabeKopfzahl);
    } else if (SystemGruppe.WAEHLER.equals(systemGruppe)) {
      setStimmeingabeKopfzahlWaehler(stimmenart, stimmeingabeKopfzahl);
    } else if (SystemGruppe.UEBRIGE.equals(systemGruppe)) {
      setStimmeingabeKopfzahlUebrige(stimmenart, stimmeingabeKopfzahl);
    } else {
      throw new IllegalArgumentException("Systemgruppe NICHT unterstützt [nlSystemGruppe = " + nlSystemGruppe + ", systemGruppe = " + systemGruppe + ", stimmenart = " + stimmenart + "]");
    }
  }
}
