package net.onthenet.nitro.formatters;

import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.webobjects.foundation.NSTimestamp;
import com.webobjects.foundation.NSTimestampFormatter;

@SuppressWarnings("deprecation")
public class OrdinalDateFormatter extends Format {
  private final Format _formatter;
  private final Pattern ORDINAL_PATTERN = Pattern.compile("([1-3]?[0-9])(?:st|nd|rd|th)");
  
  /**
   *  To include an ordinal suffix supply a format string that looks something like this:
   *   "d'th' MMM, yyyy"  where 'th' will be replaced by the correct ordinal suffix 
   *
   * @param format format string
   */
  public OrdinalDateFormatter(String format) {
    _formatter = new NSTimestampFormatter(format);
  }
  
  @Override
  public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
    NSTimestamp timestamp;
    if (obj instanceof NSTimestamp)
      timestamp = (NSTimestamp) obj;
    else if (obj instanceof java.util.Date)
      timestamp = new NSTimestamp((java.util.Date) obj);
    else if (obj instanceof java.sql.Date)
      timestamp = new NSTimestamp((java.sql.Date) obj);
    else
      throw new IllegalArgumentException("Unable to format " + obj.getClass() + " : " + obj.toString());
    
    String formatted = _formatter.format(timestamp);
    Matcher matcher = ORDINAL_PATTERN.matcher(formatted);
    if (matcher.find()) {
      formatted = matcher.replaceAll("$1" + ordinalSuffix(timestamp));
    }
    return toAppendTo.append(formatted);
  }

  private String ordinalSuffix(NSTimestamp timestamp) {
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.setTime(timestamp);
    switch (calendar.get(GregorianCalendar.DAY_OF_MONTH)) {
    case 1:
    case 21:
    case 31:
      return "st";
    case 2:
    case 22:
      return "nd";
    case 3:
    case 23:
      return "rd";
    default:
      return "th";
    }
  }

  @Override
  public Object parseObject(String source, ParsePosition pos) {
    Matcher matcher = ORDINAL_PATTERN.matcher(source);
    return _formatter.parseObject(matcher.replaceAll("$1th"), pos);
  }
}
