
package de.ivu.elect.wus.exchange.wahlvorschlag.csv;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.exchange.control.MappingException;


import static java.util.Objects.nonNull;

public abstract class AbstractWahlvorschlagCsvDTO implements WahlvorschlagCsvDTO {

  @Override
  public boolean isLeereListe() {
    return isListe() && !isKandidatur();
  }

  public boolean isListe() {
    return !isDirektkandidat() && !isErsatzkandidatur();
  }

  @Override
  public boolean isDirektkandidat() {
    return isKandidatur() && !isListenkandidatur() && !isErsatzkandidatur();
  }

  @Override
  public boolean isListenkandidatur() {
    return isKandidatur() && hasKandidaturListenposition();
  }

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

  public boolean isKandidatur() {
    return hasKandidaturFamilienname();
  }

  public boolean hasKandidaturListenposition() {
    return getKandidaturListenposition() != null;
  }

  public boolean hasKandidaturFamilienname() {
    return StringUtils.isNotBlank(getKandidaturFamilienname());
  }

  @Nullable
  protected Date getDateFromString(String kandidaturGeburtsdatumAsString, String datumFormatLong,
      String datumFormatShort, Locale locale) throws MappingException {
    if (kandidaturGeburtsdatumAsString != null) {
      String input = kandidaturGeburtsdatumAsString.trim();
      Date result;

      result = parseDate(input, datumFormatLong, locale);
      if (result != null) {
        return result;
      }

      if (nonNull(datumFormatShort)) {
        result = parseDate(input, datumFormatShort, locale);
        if (result != null) {
          return result;
        }
      }

      String exceptionMessage = "Das Datum [" + input + "] ist nicht im Format " + datumFormatLong;
      if (nonNull(datumFormatShort)) {
        exceptionMessage += " oder " + datumFormatShort;
      }
      exceptionMessage += "!";

      throw new MappingException(exceptionMessage);
    }

    return null;
  }

  @Nullable
  protected static Date parseDate(@Nonnull String input, String format, Locale locale) {
    String trimmedInput = input.trim();

    ParsePosition parsePosition = new ParsePosition(0);
    Date result = new SimpleDateFormat(format, locale).parse(input, parsePosition);

    // NOTE, dass wir hier verlangen, dass die gesamte Eingabe gelesen wird -- alles andere ist ungültig formatiert
    if (result != null && parsePosition.getIndex() >= trimmedInput.length()) {
      return result;
    }

    return null;
  }

  @Nullable
  protected String formatDate(String pattern, @Nullable Date date, Locale locale) {
    if (date == null) {
      return null;
    }
    return new SimpleDateFormat(pattern, locale).format(date);
  }

  @Nullable
  protected Long longOrNull(String value) throws MappingException {
    if (StringUtils.isBlank(value)) {
      return null;
    }
    try {
      return Long.parseLong(value);
    } catch (NumberFormatException e) {
      throw new MappingException("Zahl erwartet", e);
    }
  }

  @Nullable
  protected Boolean booleanOrNull(String value) {
    if (StringUtils.isBlank(value)) {
      return null;
    }
    return Boolean.parseBoolean(value) || "1".equals(value);
  }
}
