(function($){
  $.fn.dynamicDates = function(options){
    options = options || {}

    var now; // This is now now.
    var then; // When the event happened.
    
    var weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

    function getRelativeTime(time_value) {

      if(!time_value) return null;
      var delta = getDateOffset(time_value);
      var language = 'en';

      if (delta < 60 * 1000) {
        return get_localized('Less than a minute ago');
      } else if(happenedYesterday(delta)) {
        return format_absolute_date('Yesterday at {hours}:{minutes}{twelve_hour}', language);
      } else if(delta < 120 * 1000) {
        return get_localized('About a minute ago');
      } else if(delta < (60 * 60 * 1000)) {
        return get_localized('{minutes} minutes ago').replace(/{minutes}/, parseInt(delta / (60 * 1000)).toString());
      } else if(delta < (120 * 60 * 1000)) {
        return get_localized('About an hour ago');
      } else if(delta < (24 * 60 * 60 * 1000)) {
        return get_localized('{hours} hours ago').replace(/{hours}/, parseInt(delta / (3660 * 1000)).toString());
      } else if(delta < (7 * 24 * 60 * 60 * 1000)) {
        return format_absolute_date('{weekday} at {hours}:{minutes}{twelve_hour}', language);
      } else {
        // Dont do anything
        return;
        //return format_absolute_date('on this date at', language);
      }
    }

    function happenedYesterday(delta){
      // "yesterday" is not defined in terms of number of hours ago, but number of days.
      // It may be one minute ago or as much as 48 hours ago, but in any case exactly 24
      // hours ago can be guaranteed to be "yesterday". Therefore, provided that the event
      // is within 48 hours, and the date is equal to that of "yesterday" the event can
      // safely be assumed to have happened yesterday in all (99.9%?) of cases.
      var yesterday = new Date(now.getTime() - (24 *  60 * 60 * 1000));
      return (delta < 48 * 60 * 60 * 1000) && (yesterday.getDate() == then.getDate())
    }

    function getDateOffset(time_value) {
      // Note that Javascript does date processing in milliseconds.
      // Also, as long as the timezone information (in an accepted format) is included,
      // Javascript will calculate the timezone relative to the browser on the fly,
      // so make sure to include this in the output.
      now = new Date();
      then = new Date(time_value); // Note this converts timezones on the fly.
      return now - then;
    }

    function format_absolute_date(label, language) {
      var localized = get_localized(label);
      localized = localized.replace(/{year}/, then.getFullYear());
      var month = get_localized(then.getMonth());
      localized = localized.replace(/{month}/, month);
      localized = localized.replace(/{weekday}/, get_localized(weekdays[then.getDay()]));
      localized = localized.replace(/{date}/, then.getDate());
      localized = format_absolute_time(localized, language);
      return localized;
    }

    function format_absolute_time(localized, language) {
      var hours = then.getHours();
      var twelve_hour_affix;
      if (language == 'en') {
        // AM/PM Support only for English...weird language.
        twelve_hour_affix = get_localized('am');
        if (hours == 0) {
          hours = 12;
        } else if (hours > 11) {
          twelve_hour_affix = get_localized('pm');
          if (hours > 12) {
            hours = hours - 12;
          }
        }
      } else {
        twelve_hour_affix = '';
      }
      localized = localized.replace(/{twelve_hour}/, twelve_hour_affix);
      localized = localized.replace(/{hours}/, hours);
      localized = localized.replace(/{minutes}/, $.padNumber(then.getMinutes()));
      return localized;
    }

    function get_localized(label){
      return label;
    }

    $('[data-time]', this).each(function(i){
      var static_time = $(this).attr('data-time');
      var relative_time = getRelativeTime(static_time);
      if(relative_time){
        $(this).text(relative_time);
      }
    });
  }

  // Pads a number with zeroes (default)
  $.padNumber = function(number, padding){
    padding = padding || 2;
    number = number.toString();
    while(number.length < padding) {
      number = '0' + number;
    }
    return number;
  };

})(jQuery);

