
package de.ivu.elect.business.wahl.boundary;

import java.io.Serializable;
import java.util.Optional;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiGebietsart;
import de.ivu.elect.business.wahl.entity.UmgangBWerte;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;

public class UmgangBWerteKonfiguration implements Serializable {

  private static final long serialVersionUID = 1L;

  public UmgangBWerteKonfiguration() {
    super();
  }

  public UmgangBWerte getUmgangWaehlerOhneWahlschein(Wahl wahl, WahlartErgebnisart ergebnisart) {
    Wahlart wahlart = wahl.getWahlart();

    if (ergebnisart.isEndgueltig()) {
      return wahlart.getUmgangBOhneWahlscheinEndgueltig();
    }

    if (ergebnisart.isVorlaeufig()) {
      return wahlart.getUmgangBOhneWahlscheinVorlaeufig();
    }

    throw new IllegalArgumentException("Unbekannte Ergebnisart: " + ergebnisart);
  }

  public UmgangBWerte getUmgangWaehlerMitWahlschein(Wahl wahl, WahlartErgebnisart ergebnisart) {
    Wahlart wahlart = wahl.getWahlart();

    if (ergebnisart.isEndgueltig()) {
      return wahlart.getUmgangBMitWahlscheinEndgueltig();
    }

    if (ergebnisart.isVorlaeufig()) {
      return wahlart.getUmgangBMitWahlscheinVorlaeufig();
    }

    throw new IllegalArgumentException("Unbekannte Ergebnisart: " + ergebnisart);
  }

  public UmgangBWerte getUmgangWaehlerGesamt(Wahl wahl, WahlartErgebnisart ergebnisart) {
    Wahlart wahlart = wahl.getWahlart();

    if (ergebnisart.isEndgueltig()) {
      return wahlart.getUmgangBGesamtEndgueltig();
    }

    if (ergebnisart.isVorlaeufig()) {
      return wahlart.getUmgangBGesamtVorlaeufig();
    }

    throw new IllegalArgumentException("Unbekannte Ergebnisart: " + ergebnisart);
  }

  public boolean isWaehlerOhneWahlscheinBeiStimmeingabeRelevant(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerOhneWahlscheinBeiGebietsartRelevant(gebietsart) && getUmgangWaehlerOhneWahlschein(wahl, ergebnisart).isBWertBeiStimmeingabeZuErfassenOderAnzuzeigen();
  }

  public boolean isWaehlerOhneWahlscheinBeiStimmeingabeZuPlausibilisieren(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerOhneWahlscheinBeiGebietsartRelevant(gebietsart) && getUmgangWaehlerOhneWahlschein(wahl, ergebnisart).isBWertBeiStimmeingabeZuErfassen();
  }

  public boolean isWaehlerOhneWahlscheinBeiGebietsartRelevant(Gebiet wahldurchfuehrungsgebiet) {
    return isWaehlerOhneWahlscheinBeiGebietsartRelevant(findStimmeingabePlausiGebietsart(wahldurchfuehrungsgebiet));
  }

  public boolean isWaehlerOhneWahlscheinBeiGebietsartRelevant(Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return !isBriefwahlbezirk(gebietsart);
  }

  /**
   * @deprecated Nur zur Anzeige "potentieller" Plausis verwenden, da "Wähler ohne Wahlschein (berechnet)" keine tatsächliche Stimmeingabe ist, sondern ein Wert, der anhand von "Wähler insgesamt" und
   *             "Wähler mit Wahlschein" berechnet wird! Alle Plausis hängen dann an "Wähler insgesamt".
   */
  @Deprecated
  public boolean isWaehlerOhneWahlscheinBerechnetBeiStimmeingabeZuPlausibilisieren(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerGesamtBeiStimmeingabeZuPlausibilisieren(wahl, ergebnisart, gebietsart) && isWaehlerMitWahlscheinBeiStimmeingabeZuPlausibilisieren(wahl, ergebnisart, gebietsart);
  }

  public boolean isWaehlerMitWahlscheinBeiStimmeingabeRelevant(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerMitWahlscheinBeiGebietsartRelevant(gebietsart) && getUmgangWaehlerMitWahlschein(wahl, ergebnisart).isBWertBeiStimmeingabeZuErfassenOderAnzuzeigen();
  }

  public boolean isWaehlerMitWahlscheinBeiStimmeingabeZuPlausibilisieren(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerMitWahlscheinBeiGebietsartRelevant(gebietsart) && getUmgangWaehlerMitWahlschein(wahl, ergebnisart).isBWertBeiStimmeingabeZuErfassen();
  }

  public boolean isWaehlerMitWahlscheinBeiGebietsartRelevant(Gebiet wahldurchfuehrungsgebiet) {
    return isWaehlerMitWahlscheinBeiGebietsartRelevant(findStimmeingabePlausiGebietsart(wahldurchfuehrungsgebiet));
  }

  public boolean isWaehlerMitWahlscheinBeiGebietsartRelevant(Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return !isBriefwahlbezirk(gebietsart);
  }

  /**
   * @deprecated Nur zur Anzeige "potentieller" Plausis verwenden, da Wahldurchfuehrungsgebiet#isBriefwahlInUrneErfassenInGebietOderDarunter hier nicht bekannt ist!
   */
  @Deprecated
  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiStimmeingabeRelevant(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerMitWahlscheinInUrnenwahlAnteilInUrnenwahlAusUrnenwahlBeiWahlartRelevant(wahl) && isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiGebietsartRelevant(gebietsart);
  }

  /**
   * @deprecated Nur zur Anzeige "potentieller" Plausis verwenden, da Wahldurchfuehrungsgebiet#isBriefwahlInUrneErfassenInGebietOderDarunter hier nicht bekannt ist!
   */
  @Deprecated
  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiStimmeingabeZuPlausibilisieren(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerMitWahlscheinInUrnenwahlAnteilInUrnenwahlAusUrnenwahlBeiWahlartRelevant(wahl) && isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiGebietsartRelevant(gebietsart);
  }

  /**
   * @deprecated TODO ELECT-9319, Information muss aus einem neuen, noch zu definierenden Enum-Wert an der Wahlart kommen! Bspw. "Nur Wähler mit Wahlschein", "Wähler mit Wahlschein + davon Briefwähler
   *             (in Urnenwahllokal erfasst)", "Urnenwähler mit Wahlschein + Briefwähler (in Urnenwahllokal erfasst)"...
   *
   * @see UmgangBWerteKonfiguration#isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiWahlartRelevant
   * @see AbstractStimmeingabeKopfzahlModelBuilder#isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlCreated
   */
  @Deprecated
  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilInUrnenwahlAusUrnenwahlBeiWahlartRelevant(Wahl wahl) {
    return false;
  }

  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiGebietsartRelevant(Gebiet wahldurchfuehrungsgebiet) {
    return isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiGebietsartRelevant(findStimmeingabePlausiGebietsart(wahldurchfuehrungsgebiet));
  }

  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiGebietsartRelevant(Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return !isBriefwahlbezirk(gebietsart);
  }

  /**
   * @deprecated Nur zur Anzeige "potentieller" Plausis verwenden, da Wahldurchfuehrungsgebiet#isBriefwahlInUrneErfassenInGebietOderDarunter hier nicht bekannt ist!
   */
  @Deprecated
  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiStimmeingabeRelevant(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiWahlartRelevant(wahl) && isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiGebietsartRelevant(gebietsart);
  }

  /**
   * @deprecated Nur zur Anzeige "potentieller" Plausis verwenden, da Wahldurchfuehrungsgebiet#isBriefwahlInUrneErfassenInGebietOderDarunter hier nicht bekannt ist!
   */
  @Deprecated
  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiStimmeingabeZuPlausibilisieren(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiWahlartRelevant(wahl) && isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiGebietsartRelevant(gebietsart);
  }

  /**
   * @deprecated TODO ELECT-9319, Information muss aus einem neuen, noch zu definierenden Enum-Wert an der Wahlart kommen! Bspw. "Nur Wähler mit Wahlschein", "Wähler mit Wahlschein + davon Briefwähler
   *             (in Urnenwahllokal erfasst)", "Urnenwähler mit Wahlschein + Briefwähler (in Urnenwahllokal erfasst)"...
   *
   * @see UmgangBWerteKonfiguration#isWaehlerMitWahlscheinInUrnenwahlAnteilAusUrnenwahlBeiWahlartRelevant
   */
  @Deprecated
  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiWahlartRelevant(Wahl wahl) {
    return true; // LEGACY!
  }

  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiGebietsartRelevant(Gebiet wahldurchfuehrungsgebiet) {
    return isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiGebietsartRelevant(findStimmeingabePlausiGebietsart(wahldurchfuehrungsgebiet));
  }

  public boolean isWaehlerMitWahlscheinInUrnenwahlAnteilAusBriefwahlBeiGebietsartRelevant(Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return !isBriefwahlbezirk(gebietsart);
  }

  public boolean isWaehlerGesamtBeiStimmeingabeRelevant(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerGesamtBeiGebietsartRelevant(gebietsart) && getUmgangWaehlerGesamt(wahl, ergebnisart).isBWertBeiStimmeingabeZuErfassenOderAnzuzeigen();
  }

  public boolean isWaehlerGesamtBeiStimmeingabeZuPlausibilisieren(Wahl wahl, WahlartErgebnisart ergebnisart, Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return isWaehlerGesamtBeiGebietsartRelevant(gebietsart) && getUmgangWaehlerGesamt(wahl, ergebnisart).isBWertBeiStimmeingabeZuErfassen();
  }

  public boolean isWaehlerGesamtBeiGebietsartRelevant(Gebiet wahldurchfuehrungsgebiet) {
    return isWaehlerGesamtBeiGebietsartRelevant(findStimmeingabePlausiGebietsart(wahldurchfuehrungsgebiet));
  }

  public boolean isWaehlerGesamtBeiGebietsartRelevant(Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return true;
  }

  protected boolean isBriefwahlbezirk(Optional<StimmeingabePlausiGebietsart> gebietsart) {
    return gebietsart.map(StimmeingabePlausiGebietsart::isBriefwahlbezirk).orElse(false);
  }

  protected Optional<StimmeingabePlausiGebietsart> findStimmeingabePlausiGebietsart(Gebiet wahldurchfuehrungsgebiet) {
    return Optional.empty();
  }
}
