
package de.ivu.elect.jee.protokollierung;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import javax.annotation.Nullable;

import de.ivu.elect.jee.faces.IMessages;
import de.ivu.elect.util.ClassUtil;

public enum AttributTyp {

  OHNE {

    @Nullable
    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return null;
    }

    @Nullable
    @Override
    public Object getValueAsObject(String value) {
      return null;
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      return messages.lokalisiere(OHNE);
    }

    @Override
    public boolean isFlashbackSupported() {
      return false;
    }
  },

  @Deprecated // nicht nutzen
  LEGACY {

    @Override
    public boolean isString() {
      return STRING.isString();
    }

    @Override
    public String getValueAsString(String value) {
      return STRING.getValueAsString(value);
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      // So, wie es mal war...
      String zuSchreibenderWert;

      if (object instanceof Enum) {
        zuSchreibenderWert = messages.lokalisiere((Enum) object);
      } else if (object instanceof Date) {
        zuSchreibenderWert = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.GERMANY).format((Date) object);
      } else if (object instanceof Boolean) {
        zuSchreibenderWert = messages.lokalisiere((Boolean) object);
      } else {
        zuSchreibenderWert = object.toString();
      }

      return zuSchreibenderWert;
    }

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

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsString(value);
    }

    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      return getValueAsString(value); // nichts zu tun, bereits lokalisiert
    }
  },
  STRING {

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

    @Override
    public String getValueAsString(String value) {
      return value;
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return (String) object;
    }

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsString(value);
    }

    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      return getValueAsString(value);
    }
  },
  BOOLEAN {

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

    @Nullable
    @Override
    public Boolean getValueAsBoolean(String value) {
      if (value == null) {
        return null;
      }

      return Boolean.valueOf(value);
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return object.toString();
    }

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsBoolean(value);
    }

    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      return messages.lokalisiere(getValueAsBoolean(value));
    }
  },
  LONG {

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

    @Nullable
    @Override
    public Long getValueAsLong(String value) {
      if (value == null) {
        return null;
      }

      return Long.valueOf(value);
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return object.toString();
    }

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsLong(value);
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      Long aLong = getValueAsLong(value);

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

      return NumberFormat.getIntegerInstance(locale).format(aLong);
    }
  },
  BIG_DECIMAL {

    @Nullable
    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return object.toString();
    }

    @Nullable
    @Override
    public Object getValueAsObject(String value) {
      return getValueAsBigDecimal(value);
    }

    @Nullable
    @Override
    public BigDecimal getValueAsBigDecimal(String value) {
      if (value == null) {
        return null;
      }

      return new BigDecimal(value);
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      BigDecimal bd = getValueAsBigDecimal(value);

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

      return bd.toString();
    }
  },
  DOUBLE {

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

    @Nullable
    @Override
    public Double getValueAsDouble(String value) {
      if (value == null) {
        return null;
      }

      return Double.valueOf(value);
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return object.toString();
    }

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsDouble(value);
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      Double aDouble = getValueAsDouble(value);

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

      return NumberFormat.getNumberInstance(locale).format(aDouble);
    }
  },
  DATE {

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

    @Nullable
    @Override
    public Date getValueAsDate(String value) {
      if (value == null) {
        return null;
      }

      try {
        return new SimpleDateFormat(DATE_PATTERN).parse(value);
      } catch (ParseException e) {
        throw new RuntimeException(e.getMessage(), e);
      }
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return df.format((Date) object);
    }

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsDate(value);
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      Date aDate = getValueAsDate(value);

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

      return DateFormat.getDateInstance(DateFormat.MEDIUM, locale).format(aDate);
    }
  },
  TIMESTAMP {

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return DATE.konvertiereInZuschreibendenString(object, df, messages);
    }

    @Override
    public Object getValueAsObject(String value) {
      return DATE.getValueAsObject(value);
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      Date aDate = getValueAsDate(value);

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

      return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale).format(aDate);
    }

    @Override
    public boolean isDate() {
      return DATE.isDate();
    }

    @Nullable
    @Override
    public Date getValueAsDate(String value) {
      return DATE.getValueAsDate(value);
    }
  },
  ENUM {

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return ClassUtil.getClassName(object) + ENUM_SPLIT + object;
    }

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

    @Override
    public Object getValueAsObject(String value) {
      return getValueAsEnum(value);
    }

    @Nullable
    @Override
    public <E extends Enum> E getValueAsEnum(String value) {
      if (value == null) {
        return null;
      }

      String[] splitted = value.split("\\" + ENUM_SPLIT);

      try {
        Class aClass = Class.forName(splitted[0]);

        return (E) Enum.valueOf(aClass, splitted[1].trim().toUpperCase());
      } catch (ClassNotFoundException e) {
        throw new RuntimeException(e.getMessage(), e);
      }
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      return messages.lokalisiere(getValueAsEnum(value));
    }
  },
  LOB {

    @Override
    public boolean isString() {
      return STRING.isString();
    }

    @Override
    public String getValueAsString(String value) {
      return STRING.getValueAsString(value);
    }

    @Override
    public String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages) {
      return STRING.konvertiereInZuschreibendenString(object, df, messages);
    }

    @Override
    public Object getValueAsObject(String value) {
      return STRING.getValueAsObject(value);
    }

    @Nullable
    @Override
    public String getLocalized(String value, IMessages messages, Locale locale) {
      return STRING.getLocalized(value, messages, locale);
    }
  };

  private static final String ENUM_SPLIT = "|";

  private static final String DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";

  public boolean isString() {
    return false;
  }

  @Nullable
  public String getValueAsString(String value) {
    throw new UnsupportedOperationException();
  }

  public boolean isBoolean() {
    return false;
  }

  @Nullable
  public Boolean getValueAsBoolean(String value) {
    throw new UnsupportedOperationException();
  }

  public boolean isLong() {
    return false;
  }

  @Nullable
  public Long getValueAsLong(String value) {
    throw new UnsupportedOperationException();
  }

  public boolean isDouble() {
    return false;
  }

  @Nullable
  public Double getValueAsDouble(String value) {
    throw new UnsupportedOperationException();
  }

  public boolean isDate() {
    return false;
  }

  @Nullable
  public Date getValueAsDate(String value) {
    throw new UnsupportedOperationException();
  }

  @Nullable
  public BigDecimal getValueAsBigDecimal(String value) {
    throw new UnsupportedOperationException();
  }

  @Nullable
  public abstract String konvertiereInZuschreibendenString(Object object, DateFormat df, IMessages messages);

  public boolean isEnum() {
    return false;
  }

  @Nullable
  public abstract Object getValueAsObject(String value);

  @Nullable
  public <E extends Enum> E getValueAsEnum(String value) {
    throw new UnsupportedOperationException();
  }

  @Nullable
  public abstract String getLocalized(String value, IMessages messages, Locale locale);

  public boolean isFlashbackSupported() {
    return true;
  }

  public static DateFormat createDateFormat(Locale locale, TimeZone timeZone) {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_PATTERN, locale);
    simpleDateFormat.setTimeZone(timeZone);

    return simpleDateFormat;
  }
}
