
package de.ivu.elect.jee.presentation.dynamicform;

import static org.apache.commons.lang3.StringUtils.countMatches;

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

import javax.faces.convert.Converter;
import javax.faces.convert.DateTimeConverter;

import de.ivu.elect.jee.presentation.dynamicform.converter.AutoFormatDateTimeConverter;

public abstract class AbstractTemporalProperty extends AbstractProperty {

  protected AbstractTemporalProperty() {
    super();
  }

  public abstract boolean isShowTime(); // ELECT-12593

  @Override
  protected boolean mustBeAccessableOnPageLoadByValue() {
    if (super.mustBeAccessableOnPageLoadByValue()) {
      return true;
    }

    return notAllEqual(getDefaultValue(), getValue());
  }

  @Override
  public Converter getConverter() {
    Converter converter = super.getConverter();

    if (converter instanceof DateTimeConverter) {
      DateTimeConverter dateTimeConverter = (DateTimeConverter) converter;

      // NOTE that if there's a pattern specified, the type, dateStyle, and timeStyle properties will be ignored.
      dateTimeConverter.setPattern(getConverterPattern());
      dateTimeConverter.setLocale(getLocale());
      dateTimeConverter.setTimeZone(getTimeZone());
    }

    return converter;
  }

  @Override
  public Converter getDefaultConverter() {
    return new AutoFormatDateTimeConverter();
  }

  public String getConverterPattern() {
    // ELECT-10355, seit JDK 9 liefert DateFormat#MEDIUM als Platzhalter für das Jahr nur y (statt wie vorher yyyy), das von SimpleDateFormat allerdings
    // weiterhin vierstellig formatiert wird. Dadurch entsteht eine Diskrepanz zwischen Anzeige (vierstellig durch Converter anhand von SimpleDateFormat)
    // und Setzen eines ausgewählten Wertes (zweistellig durch das PrimeFaces-Widget).
    String result = getDateFormat().toPattern();

    if (countMatches(result, "y") == 1) {
      result = result.replace("y", "yyyy");
    }

    return result;
  }

  @Override
  protected boolean hasDefaultValue() {
    return notNullOrBlank(getDefaultValue());
  }

  public Date getDefaultValue() {
    return null;
  }

  @Override
  public boolean hasValue() {
    return notNullOrBlank(getValue());
  }

  public abstract Date getValue();

  public abstract void setValue(Date value);

  protected SimpleDateFormat getDateFormat() {
    DateFormat dateFormat = createDateFormat(getLocale());

    /*
     * From the DateFormat JavaDoc ...
     *
     * "If you want even more control over the format or parsing, (or want to give your users more control), you can try casting the DateFormat you get from the factory methods to a SimpleDateFormat.
     * This will work for the majority of countries;"
     */
    if (dateFormat instanceof SimpleDateFormat) {
      dateFormat.setTimeZone(getTimeZone());

      return (SimpleDateFormat) dateFormat;
    }

    return createDefaultDateFormat();
  }

  protected abstract DateFormat createDateFormat(Locale locale);

  protected SimpleDateFormat createDefaultDateFormat() {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
    simpleDateFormat.setTimeZone(getTimeZone());

    return simpleDateFormat;
  }
}
