
package de.ivu.elect.was.exchange.okwahl;

import static de.ivu.elect.jee.entity.EntityUtil.castTo;
import static java.util.Arrays.asList;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;

import java.util.List;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietDescriptor;
import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietInformation;
import de.ivu.elect.business.gebietsbaum.entity.ByStimmbezirkArt;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.CommonWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.exchange.BaseDTO;
import de.ivu.elect.was.exchange.DTOHavingErfassungsgebiet;
import de.ivu.elect.was.exchange.ergebnis.ErgebnisExportGebietFormatter;

public abstract class AbstractOkWahlDTO extends BaseDTO implements DTOHavingErfassungsgebiet {

  /**
   * Wird beim Export durch die Wahlart-spezifische Bezeichnung (Wahl-/Stimmkreisnummer) ersetzt!
   *
   * @see AbstractByOkWahlDTO#stimmzettelgebietNummerHeader
   */
  public static final String NAME_STIMMZETTELGEBIET_NUMMER = "Stimmzettelgebietnummer";

  public static final String NAME_STIMMZETTELGEBIET_NUMMER_LTW = "Stimmkreisnummer";

  public static final String NAME_STIMMZETTELGEBIET_NUMMER_BE = "Kreis";

  public static final String BOOLEAN_TRUE_STRING = "1";

  public static final String NAME_ERFASST = "Erfasst";

  public static final String NAME_ERFASSUNGSGEBIET_NAME = "Stimmbezirksname";

  public static final String NAME_GEMEINDEKENNZIFFER = "Gemeindekennziffer";

  public static final String NAME_GEMEINDEKENNZIFFER_BE = "Gemeinde";

  public static final String NAME_ERFASSUNGSGEBIET_NUMMER = "Stimmbezirksnummer";

  public static final String NAME_ERFASSUNGSGEBIET_ART = "Stimmbezirksart";

  private String stimmzettelgebietNummerHeader;

  public AbstractOkWahlDTO() {
    super();
  }

  protected AbstractOkWahlDTO(List<String> strings, List<String> headers) {
    if (headers.size() < strings.size()) {
      throw new RuntimeException("Header: " + headers.size() + ", line:" + strings.size());
    }
    setErfassungsgebietErfasst(parseBoolean(strings, headers, NAME_ERFASST));
    setStimmzettelgebietNummer(parseString(strings, headers, NAME_STIMMZETTELGEBIET_NUMMER, NAME_STIMMZETTELGEBIET_NUMMER_LTW, NAME_STIMMZETTELGEBIET_NUMMER_BE));
    setErfassungsgebietName(parseString(strings, headers, NAME_ERFASSUNGSGEBIET_NAME));
    setGemeindeNummer(parseString(strings, headers, NAME_GEMEINDEKENNZIFFER, NAME_GEMEINDEKENNZIFFER_BE));
    setErfassungsgebietNummer(parseString(strings, headers, NAME_ERFASSUNGSGEBIET_NUMMER));
    setErfassungsgebietArt(parseString(strings, headers, NAME_ERFASSUNGSGEBIET_ART));
  }

  @Nullable
  protected static String parseString(List<String> strings, int pos) {
    if (strings.size() < pos) {
      return null;
    }
    return strings.get(pos - 1);
  }

  @Nullable
  protected static String parseString(List<String> strings, List<String> headers, String... headerNames) {

    if (headers == null) {
      return null;
    }

    for (String headerName : headerNames) {
      int index = headers.indexOf(headerName);
      if (index >= 0) {
        return strings.get(index);
      }
    }

    return null;
  }

  protected static Boolean parseBoolean(List<String> strings, int pos) {
    String anotherString = parseString(strings, pos);
    if (anotherString == null) {
      return null;
    }
    return BOOLEAN_TRUE_STRING.equalsIgnoreCase(anotherString);
  }

  protected static Boolean parseBoolean(List<String> strings, List<String> headers, String headerName) {
    String anotherString = parseString(strings, headers, headerName);
    if (StringUtils.isBlank(anotherString)) {
      return null;
    }
    return BOOLEAN_TRUE_STRING.equalsIgnoreCase(anotherString);
  }

  @Nullable
  protected static Long parseLong(List<String> strings, int pos) {
    String anotherString = parseString(strings, pos);
    if (StringUtils.isBlank(anotherString)) {
      return null;
    }

    try {
      return Long.parseLong(anotherString);
    } catch (Exception e) {
      throw new RuntimeException("Position=" + pos + ", " + e.getMessage(), e);
    }
  }

  @Nullable
  protected static Long parseLong(List<String> strings, List<String> headers, String... headerName) {
    String anotherString = parseString(strings, headers, headerName);
    if (StringUtils.isBlank(anotherString)) {
      return null;
    }

    try {
      return Long.parseLong(anotherString);
    } catch (Exception e) {
      throw new RuntimeException("headerName" + asList(headerName) + ", " + e.getMessage(), e);
    }
  }

  public AbstractOkWahlDTO(boolean erfassungsgebietErfasst, String stimmzettelgebietNummerHeader, ErgebnisExportGebietFormatter ergebnisExportGebietFormatter,
      WahlverwaltungGebietInformation stimmzettelgebietInformation, WahlverwaltungGebietInformation gebietUebergeordnetInformation, WahlverwaltungGebietDescriptor erfassungsgebietDescriptor) {
    super();

    this.stimmzettelgebietNummerHeader = stimmzettelgebietNummerHeader;
    setStimmzettelgebietNummer(ergebnisExportGebietFormatter.formatGebietsreferenzKennungStimmzettelgebiet(stimmzettelgebietInformation));

    setGemeindeNummer(ergebnisExportGebietFormatter.formatGebietsreferenzRegionalangaben(gebietUebergeordnetInformation, erfassungsgebietDescriptor));

    Wahldurchfuehrungsgebiet erfassungsgebiet = castTo(erfassungsgebietDescriptor.getGebiet(), Wahldurchfuehrungsgebiet.class);

    setSonderinformationen(erfassungsgebiet); // ELECTKOM-172

    setErfassungsgebietErfasst(erfassungsgebietErfasst);
    setErfassungsgebietName(erfassungsgebiet.getName());
    setErfassungsgebietNummer(erfassungsgebiet.getNummerBezirkFallsGesetzt()); // ELECTKOM-171 Stimmbezirksnummer, wenn gesetzt
  }

  public abstract Boolean getErfassungsgebietErfasst();

  public abstract void setErfassungsgebietErfasst(Boolean erfassungsgebietErfasst);

  public String getStimmzettelgebietNummerHeader() {
    return stimmzettelgebietNummerHeader;
  }

  public abstract String getStimmzettelgebietNummer();

  public abstract void setStimmzettelgebietNummer(String stimmzettelgebietNummer);

  @Override
  public abstract String getErfassungsgebietName();

  public abstract void setErfassungsgebietName(String erfassungsgebietName);

  public abstract String getGemeindeNummer();

  public abstract void setGemeindeNummer(String gemeindeNummer);

  @Override
  public abstract String getErfassungsgebietNummer();

  public abstract void setErfassungsgebietNummer(String erfassungsgebietNummer);

  protected abstract String getErfassungsgebietArt();

  public abstract void setErfassungsgebietArt(String erfassungsgebietArt);

  protected static boolean isEuropawahl(Wahl wahl) {
    return CommonWahlart.EUROPAWAHL.equalsWahlart(wahl);
  }

  protected static boolean isBundestagswahl(Wahl wahl) {
    return CommonWahlart.BUNDESTAGSWAHL.equalsWahlart(wahl);
  }

  protected static boolean isBuergermeisterwahl(Wahl wahl) {
    return CommonWahlart.BUERGERMEISTERWAHL.equalsWahlart(wahl);
  }

  protected static boolean isBuergerentscheidOrVolksentscheid(Wahl wahl) {
    return isBuergerentscheid(wahl) || isVolksentscheid(wahl);
  }

  protected static boolean isBuergerentscheid(Wahl wahl) {
    return CommonWahlart.BUERGERENTSCHEID.equalsWahlart(wahl);
  }

  protected static boolean isVolksentscheid(Wahl wahl) {
    return CommonWahlart.VOLKSENTSCHEID.equalsWahlart(wahl);
  }

  // ELECTKOM-172
  public void setSonderinformationen(Gebiet gebiet) {
    String stimmbezirkArtKennzeichen = "";

    ByStimmbezirkArt stimmbezirkArt = ByStimmbezirkArt.getStimmbezirkArt(gebiet);

    if (stimmbezirkArt != null) {
      stimmbezirkArtKennzeichen = stimmbezirkArt.getKennzeichen();
    }

    setErfassungsgebietArt(defaultIfBlank(stimmbezirkArtKennzeichen, ""));
  }

  @Override
  public Boolean getSonderwahlbezirk() {
    return getByStimmbezirkArt().isSonderstimmbezirk();
  }

  @Override
  public Boolean getAuswahlbezirk() {
    return getByStimmbezirkArt().isSonderstimmbezirk();
  }

  @Override
  public Boolean getBeweglicherwahlvorstand() {
    return getByStimmbezirkArt().isBeweglicherWahlvorstand();
  }

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

  protected ByStimmbezirkArt getByStimmbezirkArt() {
    return ByStimmbezirkArt.getStimmbezirkArt(getErfassungsgebietArt());
  }

}
