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

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Date;
import java.util.Locale;

import javax.enterprise.inject.Produces;
import javax.inject.Named;

import de.ivu.elect.jee.faces.Messages;

/**
 * Diese Werte werden im Template <code>elect\common\war\src\main\webapp\WEB-INF\tags\outputTypedValue.xhtml</code> verwendet!
 */
public enum ColumnType {

  STRING {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return o.toString(); // Ganz offensichtlich wurde an einigen Stellen ColumnType.String verwendet, obwohl keine Strings als Value zurück kommen...daher kein Cast sondern Aufruf von toString()
    }
  },
  LONG {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return o.toString();
    }
  },
  DECIMAL_ONE_FRACTION_DIGIT {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return ColumnType.decimalFormat(o, "#,##0.0", locale);
    }
  },
  DECIMAL_ONE_FRACTION_DIGIT_PERCENTAGE {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      if (o instanceof Double) { // ELECTKOM-127
        NumberFormat percentInstance = NumberFormat.getPercentInstance(locale);
        percentInstance.setMinimumFractionDigits(1);

        return percentInstance.format(((Double) o));
      }

      return ColumnType.decimalFormat(o, "#,##0.0%", locale);
    }
  },
  DECIMAL_ONE_FRACTION_DIGIT_PERCENTAGE_POINTS {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return decimalFormat(o, "+#,##0.0;-#", locale, 100d);
    }
  },
  DECIMAL_TWO_FRACTION_DIGITS {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return ColumnType.decimalFormat(o, "#,##0.0#", locale);
    }
  },
  DECIMAL_TWO_FRACTION_DIGITS_PERCENTAGE {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      if (o instanceof Double) { // ELECTKOM-127
        NumberFormat percentInstance = NumberFormat.getPercentInstance(locale);
        percentInstance.setMinimumFractionDigits(2);

        return percentInstance.format(((Double) o));
      }

      return ColumnType.decimalFormat(o, "#,##0.0#%", locale);
    }
  },
  DECIMAL_TWO_FRACTION_DIGITS_PERCENTAGE_POINTS {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return decimalFormat(o, "+#,##0.0#;-#", locale, 100d);
    }
  },
  DECIMAL_THREE_FRACTION_DIGITS {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return ColumnType.decimalFormat(o, "#,##0.0##", locale);
    }
  },
  DECIMAL_THREE_FRACTION_DIGITS_PERCENTAGE {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return ColumnType.decimalFormat(o, "#,##0.0##%", locale);
    }
  },
  DECIMAL_THREE_FRACTION_DIGITS_PERCENTAGE_POINTS {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return decimalFormat(o, "+#,##0.0##;-#", locale, 100d);
    }
  },
  BOOLEAN {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return messages.lokalisiere((Boolean) o);
    }
  },
  DATE {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return DateFormat.getDateInstance(DateFormat.MEDIUM, locale).format((Date) o);
    }
  },
  TIMESTAMP {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale).format((Date) o);
    }

  },
  TIME {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return DateFormat.getTimeInstance(DateFormat.MEDIUM, locale).format((Date) o);
    }

  },
  ENUM {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return o.toString();
    }
  },
  COLLECTION() {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return o.toString();
    }
  },
  COLOR {

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

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return o.toString();
    }
  },
  BILD {

    @Override
    protected String toCsvInternal(Object o, Locale locale, Messages messages) {
      return "";
    }

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

  public boolean isString() {
    return false;
  }

  public boolean isLong() {
    return false;
  }

  public boolean isDecimalOneFractionDigit() {
    return false;
  }

  public boolean isDecimalOneFractionDigitPercentage() {
    return false;
  }

  public boolean isDecimalOneFractionDigitPercentagePoints() {
    return false;
  }

  public boolean isDecimalTwoFractionDigits() {
    return false;
  }

  public boolean isDecimalTwoFractionDigitsPercentage() {
    return false;
  }

  public boolean isDecimalTwoFractionDigitsPercentagePoints() {
    return false;
  }

  public boolean isDecimalThreeFractionDigits() {
    return false;
  }

  public boolean isDecimalThreeFractionDigitsPercentage() {
    return false;
  }

  public boolean isDecimalThreeFractionDigitsPercentagePoints() {
    return false;
  }

  public boolean isDecimalThousandsSep() {
    return false;
  }

  public boolean isBoolean() {
    return false;
  }

  public boolean isDate() {
    return false;
  }

  public boolean isTimestamp() {
    return false;
  }

  public boolean isTime() {
    return false;
  }

  public boolean isEnum() {
    return false;
  }

  public boolean isCollection() {
    return false;
  }

  public boolean isColor() {
    return false;
  }

  public boolean isBild() {
    return false;
  }

  @Produces
  @Named("defaultColumnType")
  public static ColumnType defaultColumnType() {
    return STRING;
  }

  public String toCsv(Object o, Locale locale, Messages messages) {
    if (o == null) {
      return "";
    }

    return toCsvInternal(o, locale, messages);
  }

  protected abstract String toCsvInternal(Object o, Locale locale, Messages messages);

  private static String decimalFormat(Object o, String pattern, Locale locale) {
    return decimalFormat(o, pattern, locale, 1d);
  }

  private static String decimalFormat(Object o, String pattern, Locale locale, double factor) {
    if (o instanceof Number) {
      double value = ((Number) o).doubleValue() * factor;
      DecimalFormat df = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(locale));
      return df.format(value);
    }
    return o.toString();
  }
}
