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

import java.util.Arrays;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;


import static org.apache.commons.lang3.StringUtils.stripStart;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

// Cf. ELECTMUC-131
public enum ByStimmbezirkArt {

  ALLGEMEINER_STIMMBEZIRK("0") { // ELECTMUC-2283, für allgemeine Stimmbezirke wird der Wert 0 statt Blank erwartet.

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

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) {
      return isUrnenwahlbezirk(gebiet) && !isMarkiertAlsSonderstimmbezirk(gebiet) && !isMarkiertAlsAuswahlbezirk(gebiet) && !isMarkiertAlsBeweglicherWahlvorstand(gebiet);
    }
  },

  ALLGEMEINER_STIMMBEZIRK_MIT_BEWEGLICHEM_WAHLVORSTAND("2") {

    @Override
    public boolean isBriefwahlgebiet() {
      return ALLGEMEINER_STIMMBEZIRK.isBriefwahlgebiet();
    }

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) {
      return isUrnenwahlbezirk(gebiet) && !isMarkiertAlsSonderstimmbezirk(gebiet) && !isMarkiertAlsAuswahlbezirk(gebiet) && isMarkiertAlsBeweglicherWahlvorstand(gebiet);
    }
  },

  URNENWAHL_AUSWAHLBEZIRK("3") {

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

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) {
      return isUrnenwahlbezirk(gebiet) && isMarkiertAlsAuswahlbezirk(gebiet) && !isMarkiertAlsBeweglicherWahlvorstand(gebiet);
    }
  },

  URNENWAHL_AUSWAHLBEZIRK_MIT_BEWEGLICHEM_WAHLVORSTAND("4") {

    @Override
    public boolean isBriefwahlgebiet() {
      return URNENWAHL_AUSWAHLBEZIRK.isBriefwahlgebiet();
    }

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) {
      return isUrnenwahlbezirk(gebiet) && isMarkiertAlsAuswahlbezirk(gebiet) && isMarkiertAlsBeweglicherWahlvorstand(gebiet);
    }
  },

  ALLGEMEINER_SONDERSTIMMBEZIRK("5") {

    @Override
    public boolean isBriefwahlgebiet() {
      return false; // Sonderstimmbezirk wird beim PC-Wahl/OK.WAHL-Import standardmäßig ein Stimmbezirk...
    }

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) { // ELECTKOM-172
      return isMarkiertAlsSonderstimmbezirk(gebiet) && !isMarkiertAlsAuswahlbezirk(gebiet) && !isMarkiertAlsBeweglicherWahlvorstand(gebiet);
    }
  },

  ALLGEMEINER_SONDERSTIMMBEZIRK_MIT_BEWEGLICHEM_WAHLVORSTAND("6") {

    @Override
    public boolean isBriefwahlgebiet() {
      return ALLGEMEINER_SONDERSTIMMBEZIRK.isBriefwahlgebiet();
    }

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) { // ELECTKOM-172
      return isMarkiertAlsSonderstimmbezirk(gebiet) && !isMarkiertAlsAuswahlbezirk(gebiet) && isMarkiertAlsBeweglicherWahlvorstand(gebiet);
    }
  },

  ALLGEMEINER_BRIEFWAHLBEZIRK("1") {

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

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) {
      return isBriefwahlbezirk(gebiet) && !isMarkiertAlsSonderstimmbezirk(gebiet) && !isMarkiertAlsAuswahlbezirk(gebiet);
    }
  },

  // ALLGEMEINER_BRIEFWAHLBEZIRK_MIT_BEWEGLICHEM_WAHLVORSTAND("?") -> ALLGEMEINER_BRIEFWAHLBEZIRK("1")

  BRIEFWAHL_AUSWAHLBEZIRK("7") {

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

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

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

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

    @Override
    public boolean matchesStimmbezirkArt(Gebiet gebiet) {
      return isBriefwahlbezirk(gebiet) && isMarkiertAlsAuswahlbezirk(gebiet);
    }
  }

  // BRIEFWAHL_AUSWAHLBEZIRK_MIT_BEWEGLICHEM_WAHLVORSTAND("?") -> BRIEFWAHL_AUSWAHLBEZIRK("7")

  ;

  private final String kennzeichen;

  ByStimmbezirkArt(String kennzeichen) {
    this.kennzeichen = kennzeichen;
  }

  public abstract boolean matchesStimmbezirkArt(Gebiet gebiet);

  public boolean isUrnenwahlgebiet() {
    return !isBriefwahlgebiet();
  }

  public abstract boolean isBriefwahlgebiet();

  public String getKennzeichen() {
    return kennzeichen;
  }

  protected boolean isUrnenwahlbezirk(Gebiet gebiet) {
    return !isBriefwahlbezirk(gebiet);
  }

  protected boolean isBriefwahlbezirk(Gebiet gebiet) {
    return gebiet.isBriefwahlgebiet();
  }

  protected boolean isMarkiertAlsSonderstimmbezirk(Gebiet gebiet) {
    return Boolean.TRUE.equals(gebiet.getSonderstimmbezirk());
  }

  protected boolean isMarkiertAlsAuswahlbezirk(Gebiet gebiet) {
    return Boolean.TRUE.equals(gebiet.getAuswahlbezirk());
  }

  protected boolean isMarkiertAlsBeweglicherWahlvorstand(Gebiet gebiet) {
    return Boolean.TRUE.equals(gebiet.getBeweglicherWahlvorstand());
  }

  public abstract boolean isSonderstimmbezirk();

  public abstract boolean isAuswahlbezirk();

  public abstract boolean isBeweglicherWahlvorstand();

  public void setzeAnGebiet(Gebiet gebiet) {
    gebiet.setBeweglicherWahlvorstand(isBeweglicherWahlvorstand());
    gebiet.setAuswahlbezirk(isAuswahlbezirk());
    gebiet.setSonderstimmbezirk(isSonderstimmbezirk());
  }

  public static ByStimmbezirkArt getStimmbezirkArt(String kennzeichen) {
    String another = normalizeKennzeichen(kennzeichen);

    if (StringUtils.isBlank(kennzeichen)) {
      return ALLGEMEINER_STIMMBEZIRK; // fallback
    }

    return Arrays.stream(values()).filter(stimmbezirkArt -> normalizeKennzeichen(stimmbezirkArt.getKennzeichen()).equalsIgnoreCase(another)).findFirst()
      .orElse(ALLGEMEINER_STIMMBEZIRK); // fallback

  }

  private static String normalizeKennzeichen(String kennzeichen) {
    String result = trimToEmpty(kennzeichen);

    if (result.length() > 1) {
      result = stripStart(result, "0");

      if (result.isEmpty()) {
        result = "0";
      }
    }

    return result;
  }

  @Nullable
  public static ByStimmbezirkArt getStimmbezirkArt(@Nullable Gebiet gebiet) {
    if (gebiet == null) {
      return null;
    }

    return Arrays.stream(values()).filter(stimmbezirkArt -> stimmbezirkArt.matchesStimmbezirkArt(gebiet)).findFirst().orElse(null);
  }
}
