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

import static de.ivu.elect.business.wahl.entity.WahlartSitzberechnungsalgorithmus.KEIN;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.startsWithAny;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.EnumSet;
import java.util.Set;
import java.util.function.Supplier;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.NlGebiet;
import de.ivu.elect.business.gebietsbaum.entity.NlGebietsart;
import de.ivu.elect.business.security.Customer;
import de.ivu.elect.business.wahl.boundary.WahlartTemplate;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.presentation.NlElectionLevel;

/**
 * Beachte: https://support.elect-it.com/wiki/display/ELECT/Wahlarten+in+VAPP
 */
public enum NlWahlart implements WahlartTemplate {

  EERSTE_KAMER {

    @Override
    public String getWahlartName() {
      return "EK";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.STAAT);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.PROVINCIE);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.PROVINCIE);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "alle"; // ??
    }

    @Override
    protected int getNominierungAnzahlDerTageVorWahltag() {
      return 34; // ELECT-9642
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 100;
    }

    @Override
    public boolean isPersonenregisterAbgleichUnterstuetzt() {
      return true;
    }
  },

  TWEEDE_KAMER {

    @Override
    public String getWahlartName() {
      return "TK";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.STAAT);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.KIESKRING);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK /* ELECTVAPP-1203 */);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "alle";
    }

    @Override
    public boolean isSupportedInMasterElectionTree() {
      return true;
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 25;
    }

    @Override
    public boolean isBriefwahlAuslandUnterstuetzt() {
      return true;
    }

    @Override
    public boolean isPersonenregisterAbgleichUnterstuetzt() {
      return true;
    }
  },

  EUROPEES_PARLEMENT {

    @Override
    public String getWahlartName() {
      return "EP";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.STAAT);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.KIESKRING);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK /* ELECTVAPP-1203 */);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "alle"; // ???
    }

    @Override
    protected int getNominierungAnzahlDerTageVorWahltag() {
      return 45; // ELECT-9642
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 10;
    }

    @Override
    public boolean isBriefwahlAuslandUnterstuetzt() {
      return true;
    }

    @Override
    public boolean isPersonenregisterAbgleichUnterstuetzt() {
      return true;
    }
  },

  GEMEENTERAAD {

    @Override
    public String getWahlartName() {
      return "GR";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK/* ELECTVAPP-1203 */);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK/* ELECTVAPP-1203 */);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK/* ELECTVAPP-1203 */);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "geen";
    }

    @Override
    public boolean isSupportedInMasterElectionTree() {
      return true;
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      if (anzahlSitze != null && anzahlSitze < 19) {
        return 50;
      }
      return 25;
    }
  },
  // ELECT-9645 deaktiviert
  //  KIESCOLLEG {
  //    @Override
  //    public String getWahlartName() {
  //      return "KC"; //  "KC" kann nicht stimmen muss ein Wert aus de.ivu.wahl.wus.oasis.eml.kiesraad.ElectionCategoryType sein
  //    }
  //
  //    @Override
  //    public NlGebietsart getCsb() {
  //      return NlGebietsart.UNBEKANNT;
  //    }
  //
  //    @Override
  //    public NlGebietsart getHsb() {
  //      return NlGebietsart.UNBEKANNT;
  //    }
  //
  //    @Override
  //    public NlGebietsart getPsb() {
  //      return NlGebietsart.UNBEKANNT;
  //    }
  //
  //  },

  EILANDSRAAD {

    @Override
    public String getWahlartName() {
      return "ER";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.OPENBAAR_LICHAAM);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.OPENBAAR_LICHAAM);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.OPENBAAR_LICHAAM);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "geen"; // ???
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return GEMEENTERAAD.getPreferencialBarrierNumerator(anzahlSitze);
    }
  },

  @Deprecated // Nur für die Definition einer PROVINCIALE_STATEN WAHL notwendig - eine konkrete Wahl ist dann PS1 oder PS2
  PROVINCIALE_STATEN {

    @Override
    public boolean isWahlartFuerDurchfuehrbareWahl() {
      return false; // MUSS PS1 oder PS2 sein(!)
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 25;
    }

    @Override
    public String getWahlartName() {
      return "PS";
    }

    @Override
    public boolean equalsWahlart(String wahlartName) {
      return getWahlartName().equalsIgnoreCase(wahlartName); // nur bei exaktem Treffer (nicht startsWith)
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.UNBEKANNT); // erst bei PS1/PS2 klar
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.UNBEKANNT);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.UNBEKANNT);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "geen"; // ???
    }
  },
  PROVINCIALE_STATEN1/* EIN WAHLKREIS */ {

    @Override
    public String getWahlartName() {
      return "PS_PS1";
    }

    @Override
    public String getKennzeichen() {
      return "PS";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.PROVINCIE);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.PROVINCIE);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK /* ELECTVAPP-1203 */);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return PROVINCIALE_STATEN.getEml110ContestIdentifier();
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return PROVINCIALE_STATEN.getPreferencialBarrierNumerator(anzahlSitze);
    }
  },

  PROVINCIALE_STATEN2/* MEHRERE WAHLKREISE */ {

    @Override
    public String getWahlartName() {
      return "PS_PS2";
    }

    @Override
    public String getKennzeichen() {
      return "PS";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.PROVINCIE);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.KIESKRING);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK /* ELECTVAPP-1203 */);
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return PROVINCIALE_STATEN.getPreferencialBarrierNumerator(anzahlSitze);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return PROVINCIALE_STATEN.getEml110ContestIdentifier();
    }
  },

  REFERENDUM/* National */ {

    @Override
    public String getWahlartName() {
      return "NR";
    }

    @Override
    public String getKennzeichen() {
      return "NR"; // aus EML(?)
    }

    @Override
    public CommonWahlart getCommonWahlart() {
      return CommonWahlart.VOLKSENTSCHEID;
    }

    @Override
    protected boolean isListenwahl() {
      return false;
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.STAAT);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.KIESKRING);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK/* ELECTVAPP-1203 */);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "geen"; // ???
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 0;
    }

    @Override
    protected boolean isReferendum() {
      return true;
    }

    @Override
    public boolean isBriefwahlAuslandUnterstuetzt() {
      return true;
    }
  },

  WATERSCHAP {

    @Override
    public String getWahlartName() {
      return "AB";
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.WATERSCHAP);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.WATERSCHAP);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.GEMEENTE, NlGebietsart.GEMEENTE_FRYSK/* ELECTVAPP-1203 */);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "geen"; // ???
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 25;
    }
  },

  UNBEKANNT /* ELECT-9627 */ {

    @Override
    public String getWahlartName() {
      return "<UNBEKANNT>";
    }

    @Override
    protected boolean isReferendum() {
      return false;
    }

    @Override
    protected boolean isListenwahl() {
      return false;
    }

    @Override
    public boolean isBekannteWahlart() {
      return false;
    }

    @Override
    public Set<NlGebietsart> getCsbs() {
      return EnumSet.of(NlGebietsart.UNBEKANNT);
    }

    @Override
    public Set<NlGebietsart> getHsbs() {
      return EnumSet.of(NlGebietsart.UNBEKANNT);
    }

    @Override
    public Set<NlGebietsart> getPsbs() {
      return EnumSet.of(NlGebietsart.UNBEKANNT);
    }

    @Override
    public String getEml110ContestIdentifier() {
      return "";
    }

    @Override
    public boolean isWahlartFuerDurchfuehrbareWahl() {
      return false;
    }

    @Override
    public long getPreferencialBarrierNumerator(Long anzahlSitze) {
      return 0;
    }

  };

  /**
   * Weitere Wahlarten aus http://bitbucket.local.elect-it.com/projects/RETIRED/repos/osv/browse/de.ivu.wahl.wus.electioncategory/src/main/java/de/ivu/wahl/wus/electioncategory/ElectionCategory.java
   * NATIONAL_REFERENDUM {
   *
   * @Override public String getWahlartTitel() { return "National referendum"; }
   *
   * @Override public CommonWahlart getCommonWahlart() { return CommonWahlart.BEGEHREN; }
   *
   * @Override public WahlartSitzberechnungsalgorithmus getSitzberechnungsalgorithmus() { return WahlartSitzberechnungsalgorithmus.KEIN; }
   *
   * @Override public String getKennzeichen() { return "NR"; }
   *
   * @Override public boolean equalsWahlart(Wahlart wahlart) { return wahlart != null && wahlart.getWahlartName().contains("National Referendum"); } },
   *
   *           PROVINCIAL_REFERENDUM {
   *
   * @Override public String getWahlartTitel() { return "Provincial referendum"; }
   *
   * @Override public CommonWahlart getCommonWahlart() { return CommonWahlart.BEGEHREN; }
   *
   * @Override public WahlartSitzberechnungsalgorithmus getSitzberechnungsalgorithmus() { return WahlartSitzberechnungsalgorithmus.KEIN; }
   *
   * @Override public String getKennzeichen() { return "PR"; }
   *
   * @Override public boolean equalsWahlart(Wahlart wahlart) { return wahlart != null && wahlart.getWahlartName().contains("Referendum"); } },
   *
   *           LOCAL_REFERENDUM {
   *
   * @Override public String getWahlartTitel() { return "Local referendum"; }
   *
   * @Override public CommonWahlart getCommonWahlart() { return CommonWahlart.BEGEHREN; }
   *
   * @Override public WahlartSitzberechnungsalgorithmus getSitzberechnungsalgorithmus() { return WahlartSitzberechnungsalgorithmus.KEIN; }
   *
   * @Override public String getKennzeichen() { return "LR"; }
   *
   * @Override public boolean equalsWahlart(Wahlart wahlart) { return wahlart != null && wahlart.getWahlartName().contains("Local Referendum"); } },
   *
   *           ISLANDS_REFERENDUM {
   * @Override public String getWahlartTitel() { return "Islands referendum"; }
   *
   * @Override public CommonWahlart getCommonWahlart() { return CommonWahlart.BEGEHREN; }
   *
   * @Override public WahlartSitzberechnungsalgorithmus getSitzberechnungsalgorithmus() { return WahlartSitzberechnungsalgorithmus.KEIN; }
   *
   * @Override public String getKennzeichen() { return "IR"; }
   *
   * @Override public boolean equalsWahlart(Wahlart wahlart) { return wahlart != null && wahlart.getWahlartName().contains("Referendum"); }
   *
   *           };
   */
  /**
   * Bestuurscommissie - Amsterdam BC(0x41), Gebiedscommissie - Rotterdam GC(0x42), Waterschapsverkiezing AB(0x43)
   */

  public static final String KUERZEL_WAHLEBENE_CSB = "CSB"; // Wahlgebiet - Sitzberechnung

  public static final String KUERZEL_WAHLEBENE_HSB = "HSB"; // Aggregationsebene

  public static final String KUERZEL_WAHLEBENE_PSB = "PSB"; // Erfassungsebene

  NlWahlart() {
  }

  @Override
  public CommonWahlart getCommonWahlart() {
    return CommonWahlart.UNBEKANNT;
  }

  @Override
  public String getKennzeichen() {
    return getWahlartName();
  }

  @Override
  public WahlartSitzberechnungsalgorithmus getSitzberechnungsalgorithmus() {
    return KEIN;
  }

  @Override
  public boolean equalsWahlart(Wahlart wahlart) { // "Eerste Kamer" == "Eerste Kamer (Kiesraad)"!
    return WahlartTemplate.super.equalsWahlart(wahlart) || wahlart != null && equalsWahlart(wahlart.getWahlartName());
  }

  public boolean equalsWahlart(String wahlartName) {
    if (isNotBlank(wahlartName)) {
      String another = CommonWahlart.normalizeWahlartName(wahlartName);

      return startsWithAny(another, CommonWahlart.normalizeWahlartName(getWahlartName()), CommonWahlart.normalizeWahlartName(name()));
    }

    return false;
  }

  public boolean isBekannteWahlart() {
    return true;
  }

  public boolean isBriefwahlGemeindeUnterstuetzt() {
    return true; // ELECTVAPP-1152
  }

  public boolean isBriefwahlAuslandUnterstuetzt() {
    return false;
  }

  protected boolean isReferendum() {
    return false;
  }

  protected boolean isListenwahl() {
    return true;
  }

  public abstract Set<NlGebietsart> getCsbs();

  public abstract Set<NlGebietsart> getHsbs();

  public abstract Set<NlGebietsart> getPsbs();

  public abstract String getEml110ContestIdentifier();

  public boolean isPersonenregisterAbgleichUnterstuetzt() {
    return false;
  }

  public static boolean isBriefwahlGemeindeUnterstuetzt(Gebiet gebietImGebietsbaum) {
    if (gebietImGebietsbaum != null) {
      Wahl wahl = gebietImGebietsbaum.getWahl();

      if (wahl != null) {
        boolean briefwahlGemeindeUnterstuetzt = valueOf(wahl.getWahlart()).isBriefwahlGemeindeUnterstuetzt();

        return gebietImGebietsbaum.getGebietshierarchie().stream() //
            .map(NlGebiet::new) //
            .anyMatch(gebietInGebietshierarchie -> gebietInGebietshierarchie.isBriefwahlgebietGemeinde()
                || briefwahlGemeindeUnterstuetzt && gebietInGebietshierarchie.isBriefwahlGemeindeInGebietshierarchieUnterhalbZulaessig());
      }
    }

    return false;
  }

  public static boolean isBriefwahlAuslandUnterstuetzt(Gebiet gebietImGebietsbaum) {
    if (gebietImGebietsbaum != null) {
      Wahl wahl = gebietImGebietsbaum.getWahl();

      if (wahl != null) {
        boolean briefwahlAuslandUnterstuetzt = valueOf(wahl.getWahlart()).isBriefwahlAuslandUnterstuetzt();

        return gebietImGebietsbaum.getGebietshierarchie().stream() //
            .map(NlGebiet::new) //
            .anyMatch(gebietInGebietshierarchie -> gebietInGebietshierarchie.isBriefwahlgebietAusland()
                || briefwahlAuslandUnterstuetzt && gebietInGebietshierarchie.isBriefwahlAuslandInGebietshierarchieUnterhalbZulaessig());
      }
    }

    return false;
  }

  public static boolean isListenwahl(Wahl wahl) {
    return wahl != null && isListenwahl(wahl.getWahlart());
  }

  public static boolean isListenwahl(Wahlart wahlart) {
    return wahlart != null && valueOf(wahlart).isListenwahl();
  }

  public static Collection<NlWahlart> valuesListenwahl() {
    return stream(NlWahlart.values()).filter(NlWahlart::isListenwahl).collect(toSet());
  }

  public static boolean isReferendum(Wahl wahl) {
    return wahl != null && valueOf(wahl.getWahlart()).isReferendum();
  }

  public static Collection<NlWahlart> valuesReferendum() {
    return stream(NlWahlart.values()).filter(NlWahlart::isReferendum).collect(toSet());
  }

  public static NlWahlart valueOf(Wahl wahl) {
    if (wahl == null) {
      return UNBEKANNT;
    }

    return valueOf(wahl.getWahlart());
  }

  public static NlWahlart valueOf(Wahlart wahlart) {
    return stream(values()).filter(value -> value.equalsWahlart(wahlart)).findFirst().orElse(UNBEKANNT);
  }

  public static boolean isWasHSB(Wahl wahl, Customer customer) {
    if (wahl == null) {
      return false;
    }

    return isWasHSB(wahl.getWahlart(), customer);
  }

  public static boolean isWasHSB(Wahlart wahlart, Customer customer) {
    return isWas(customer) && equalsWahlebene(wahlart, KUERZEL_WAHLEBENE_HSB);
  }

  public static boolean isWasCSB(Wahl wahl, Customer customer) {
    return wahl != null && isWasCSB(wahl.getWahlart(), customer);
  }

  public static boolean isWasCSB(Wahlart wahlart, Customer customer) {
    return isWas(customer) && equalsWahlebene(wahlart, KUERZEL_WAHLEBENE_CSB);
  }

  public static boolean isWasPSB(Wahl wahl, Customer customer) {
    return wahl != null && isWasPSB(wahl.getWahlart(), customer);
  }

  public static boolean isWasPSB(Wahlart wahlart, Customer customer) {
    return isWas(customer) && equalsWahlebene(wahlart, KUERZEL_WAHLEBENE_PSB);
  }

  public static boolean equalsWahlebene(Wahl wahl, String nameEbene) {
    return wahl != null && equalsWahlebene(wahl.getWahlart(), nameEbene);
  }

  public static boolean equalsWahlebene(Wahlart wahlart, String nameEbene) {
    if (wahlart == null || isBlank(wahlart.getName())) {
      return false;
    }

    return equalsWahlebene(wahlart.getName(), nameEbene);
  }

  public static boolean equalsWahlebene(String wahlartName, String nameEbene) {
    return isNotBlank(wahlartName) && wahlartName.toUpperCase().contains(nameEbene);
  }

  // vgl PS/PS1/PS2
  public boolean isWahlartFuerDurchfuehrbareWahl() {
    return true;
  }

  public static Date getNominationDate(Wahl wahl) {
    return NlWahlart.valueOf(wahl).getNominationDateFromWahl(wahl);
  }

  public Date getNominationDateFromWahl(Wahl wahl) {
    Date wahldatum = wahl.getWahldatum();

    if (wahldatum != null) {
      Calendar calendar = Calendar.getInstance(); // this would default to now
      calendar.setTime(wahldatum);
      calendar.add(Calendar.DAY_OF_MONTH, -getNominierungAnzahlDerTageVorWahltag());

      return calendar.getTime();
    }

    return wahldatum;
  }

  protected int getNominierungAnzahlDerTageVorWahltag() {
    return 44; // ELECT-9642
  }

  public static boolean isWasGemeinde(Supplier<Gebiet> wurzelgebiet, Customer customer) {
    // nur für Gemeinden in VAPP-U (WAS) zulässig
    // https://support.elect-it.com/wiki/display/ELECT/Wahlarten+in+VAPP
    return isWas(customer) && NlGebietsart.from(wurzelgebiet.get()).isGemeinde();
  }

  public static boolean isWas(Customer customer) {
    return Customer.NL_WAS.equals(customer);
  }

  public static boolean isWus(Customer customer) {
    return Customer.NL_WUS.equals(customer) /* && isEbene(wahlart, "DEF") */;
  }

  public boolean isSupportedInMasterElectionTree() {
    return false; // einzeln freischalten, muss in Wahldefinition (nl-interfaces-met) unterstützt werden
  }

  public static boolean isZurAuswahlInWus(Wahlart wahlart) {
    return NlWahlart.valueOf(wahlart).isSupportedInMasterElectionTree() && isDefinitionIgnoreCustomer(wahlart);
  }

  public static boolean isDefinitionIgnoreCustomer(Wahlart wahlart) {
    return equalsWahlebene(wahlart, "DEF");
  }

  public static boolean matches(Wahlart wahlart, NlElectionLevel electionLevel, Customer customer) {
    return electionLevel.isCSB() == isWasCSB(wahlart, customer) && electionLevel.isHSB() == isWasHSB(wahlart, customer) && electionLevel.isPSB() == isWasPSB(wahlart, customer);
  }

  public abstract long getPreferencialBarrierNumerator(Long anzahlSitze);

  public static String bestimmeWahlNamen(Messages messages, Wahlart wahlart, Gebiet gebiet, Date wahldatum) {
    // ELECTVAPP-1549
    String gebietName = "";
    if (gebiet != null) {
      gebietName = gebiet.getName();
    }

    String wahljahr = new SimpleDateFormat("yyyy").format(wahldatum);

    return messages.getMessageForMessageKey("wahl.name." + wahlart.getKennzeichen(), gebietName, wahljahr);
  }
}
