Object.extend(Date.prototype, {
  /**
   * @param format {String} The string used to format the date.
   * Example:  new Date().strftime("%A %I:%M %p")
   */
  strftime: function(format) {
    var day = this.getUTCDay(), month = this.getUTCMonth();
    var hours = this.getUTCHours(), minutes = this.getUTCMinutes();
    function pad(num) { return num.toPaddedString(2); };

    return format.gsub(/\%([aAbBcdDHiImMpSwyY])/, function(part) {
      switch(part[1]) {
        case 'a': return $w("Sun Mon Tue Wed Thu Fri Sat")[day]; break;
        case 'A': return $w("Sunday Monday Tuesday Wednesday Thursday Friday Saturday")[day]; break;
        case 'b': return $w("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")[month]; break;
        case 'B': return $w("January February March April May June July August September October November December")[month]; break;
        case 'c': return this.toString(); break;
        case 'd': return this.getUTCDate(); break;
        case 'D': return pad(this.getUTCDate()); break;
        case 'H': return pad(hours); break;
        case 'i': return (hours === 12 || hours === 0) ? 12 : (hours + 12) % 12; break;
        case 'I': return pad((hours === 12 || hours === 0) ? 12 : (hours + 12) % 12); break;
        case 'm': return pad(month + 1); break;
        case 'M': return pad(minutes); break;
        case 'p': return hours > 11 ? 'PM' : 'AM'; break;
        case 'S': return pad(this.getUTCSeconds()); break;
        case 'w': return day; break;
        case 'y': return pad(this.getUTCFullYear() % 100); break;
        case 'Y': return this.getUTCFullYear().toString(); break;
      }
    }.bind(this));
  }
});

var DateHelper = {
  
  time_ago_in_words: function(from) {
    return this.distance_of_time_in_words(new Date, from);
  },

  distance_of_time_in_words: function(to, from) {
    var distance_in_seconds = ((to - from) / 1000);
    return this.distance_string_for_seconds(distance_in_seconds)
  },
  
  distance_string_for_seconds: function (distance_in_seconds) {
      
      var distance_in_minutes = (distance_in_seconds / 60).floor();
      
      if (distance_in_minutes == 0) { return 'just now'; }
      if (distance_in_minutes == 1) { return 'a minute ago'; }
      if (distance_in_minutes < 45) { return distance_in_minutes + ' minutes ago'; }
      if (distance_in_minutes < 90) { return 'about an hour ago'; }
      if (distance_in_minutes < 1440) { return 'about ' + (distance_in_minutes / 60).round() + ' hours ago'; }
      if (distance_in_minutes < 2880) { return '1 day ago'; }
      if (distance_in_minutes < 43200) { return (distance_in_minutes / 1440).round() + ' days ago'; }
      if (distance_in_minutes < 86400) { return 'about 1 month ago'; }
      if (distance_in_minutes < 525960) { return (distance_in_minutes / 43200).round() + ' months ago'; }
      if (distance_in_minutes < 1051199) { return 'about 1 year ago'; }

      return 'over ' + (distance_in_minutes / 525960).floor() + ' years ago';
      
  }
  
};


function prettifyTimes() {
    $$("abbr.time").each(function(element){
        replaceTimeWithCurrentTime(element);
    });
}

document.observe("dom:loaded", function() {
    prettifyTimes();
    setInterval(prettifyTimes, 5000);
});

function replaceTimeWithCurrentTime(element) {
    var utcString = element.title;
    var utcDate = date_from_microformat(utcString);
    var timeSinceDate = seconds_since(local_date_from_gmt_date(utcDate));
    var timeSinceDateInWords = DateHelper.distance_string_for_seconds(timeSinceDate);
    var showOnline = element.hasClassName("online") ? true : false;
    var showRelativeTimes = element.hasClassName("absolute") ? false : true;
        
    // If it's less than five minutes old, and we want to see online times, do that.
    if (timeSinceDate < 5 * 60 && showOnline) {
        element.innerHTML = "<span class=\"now\">online now</span>";
        return;
    }
    // If it's less than two hours old, use relative time.
    if (timeSinceDate < 2 * 60 * 60 && showRelativeTimes) {
        element.innerHTML = timeSinceDateInWords;
        return;
    }
    
    element.innerHTML = readable_date(utcDate);
}

function readable_date(date) {
    date = local_date_from_gmt_date(date);
    var string = date.strftime("%b %d, ");
    var timeString = date.strftime("%I:%M%p");
    timeString = trimLeadingZero(timeString);
    string = string + timeString;
    string = string.sub("PM", "pm").sub("AM", "am");
    string.gsub(/ 0(\d\D)/, ' \1');
    return string;
}

function date_from_microformat(dateString){
 var theTime = ('' + dateString).replace(/-/g,"/").replace(/[TZ]/g," "),
     dt = new Date(),
     seconds = ((dt - new Date(theTime) + (dt.getTimezoneOffset() * 60000)) / 1000),
     token = ' Ago',
     i = 0,
     format;
        
   return new Date(theTime);
}

function local_date_from_gmt_date(gmtDate){
    var gmtOffsetHours = -new Date().getTimezoneOffset() / 60;
    return add_hours_to_date(gmtDate, gmtOffsetHours);
}

function add_hours_to_date(date, hours) {
    date.setHours(date.getHours() + hours);
    return date;
}

function seconds_between(date1, date2) {
    return (date1 - date2) / 1000;
}

function seconds_since(date) {
    return seconds_between(new Date(), date);
}


function trimLeadingZero(s) { 
    return s.replace(/^0+/, ''); 
} 
