// relativedates.js
// Nathan Ashby-Kuhlman
// 2002-12-19
//
// I'm hereby releasing date script into the public domain.
// Do whatever you want with it, especially if you want to make it better.

var monthAbbreviations = new Array("Jan. ", "Feb. ", "March ", "April ", "May ", "June ", "July ", "Aug. ", "Sept. ", "Oct. ", "Nov. ", "Dec. ");
var daysOfTheWeek = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
var exports = typeof exports === "undefined" ? window : exports;

// In milliseconds:
var SECOND = 1000;
var MINUTE = SECOND * 60;
var HOUR = MINUTE * 60;
var DAY = HOUR * 24;
var WEEK = DAY * 7;
var ONEDAYAGO = -86400000;
var ONEDAYFROMNOW = 86400000;
var TWODAYSAGO = -172800000;
var SEVENDAYSAGO = -604800000;
var SIXDAYSFROMNOW = 518400000;

var dateReference = exports.dateReference = function(dateString) {
    var relative = relativeDate(dateString);
    var explicit = explicitDate(dateString, true);
    if (relative != explicit) {
        document.write("<acronym title=\"" + explicit + "\">" + relative + "</acronym>");
    } else {
        document.write(explicit);
    }
};

var relativeDate = exports.relativeDate = function(dateString) {
    var now = new Date();
    var reference;
    
    if (typeof(dateString) === "string") {
        reference = new Date(dateString);
        if (isNaN(reference)) {
            try {
                reference = new Date(exports.parseISO8601(dateString));
                dateString = reference;
            } catch (err) {
                return dateString;
            }
        }
    } else {
        reference = dateString;
    }

    if (isNaN(reference)) return dateString;
    // Calculate time offset between the two dates
    var offset = reference.getTime() - now.getTime();

    if (offset <= 0) {
        offset = Math.abs(offset);
        if (offset < MINUTE) {
            var seconds = Math.round(offset / SECOND);
            if (seconds === 1) {
                return "1 second ago";
            }
            return  seconds + " seconds ago";
        }
        if (offset < HOUR) {
            var minutes = Math.round(offset / MINUTE);
            if (minutes === 1) {
                return "1 minute ago";
            }
            return minutes + " minutes ago";
        }
        if (offset < DAY) {
            var hours = Math.round(offset / HOUR);
            if (hours === 1) {
                return "1 hour ago";
            }
            return hours + " hours ago";
        }
        if (offset < WEEK) {
            var days = Math.round(offset / DAY);
            if (days === 1) {
                return "yesterday";
            }
            return days + " days ago";
        }
    }

    // Today, tomorrow, yesterday
    if ((offset > ONEDAYAGO) && (offset <= 0)) {
        return Math.round(offset) + " minutes ago";
    }
    if ((offset > ONEDAYAGO) && (offset <= 0)) return "today";
    if ((offset > 0) && (offset < ONEDAYFROMNOW )) return "tomorrow";
    if ((offset > TWODAYSAGO) && (offset <= ONEDAYAGO)) return "yesterday";

    // Past week or coming week
    if ((offset > SEVENDAYSAGO) && (offset <= TWODAYSAGO)) return "last " + daysOfTheWeek[reference.getDay()];
    if ((offset >= ONEDAYFROMNOW) && (offset < SIXDAYSFROMNOW)) return "date " + daysOfTheWeek[reference.getDay()];

    // None of the above
    return explicitDate(dateString, false);
};

var explicitDate = exports.explicityDate = function(dateString, includeYearRegardless) {
    var now = new Date();
    var reference = new Date(dateString);
    if (isNaN(reference)) return dateString;
    var date = reference.getDate();
    var month = monthAbbreviations[reference.getMonth()];
    // Unless specified, only include the year if it is different from the current year
    if ((reference.getFullYear() != now.getFullYear()) || includeYearRegardless) {
        var year = ", " + reference.getFullYear();
    } else {
        var year = "";
    }
    return(month + date + year);
};

exports.parseISO8601 = function (string) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = string.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);
    var time;

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]); }
    if (d[7]) { date.setHours(d[7]); }
    if (d[8]) { date.setMinutes(d[8]); }
    if (d[10]) { date.setSeconds(d[10]); }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    time = (Number(date) + (offset * 60 * 1000));
    date.setTime(Number(time));
    return date;
};

exports.toISOString = function(date) {
    var year = date.getUTCFullYear();
    var month = (date.getUTCMonth() + 1).toString();
    month  = month.length === 1 ? "0"+month : month;

    var day = date.getUTCDate().toString();
    day = day.length === 1 ? "0"+day : day;

    var hours = date.getUTCHours().toString();
    hours = hours.length === 1 ? "0"+hours : hours;

    var minutes = date.getUTCMinutes().toString();
    minutes = minutes.length === 1 ? "0"+minutes : minutes;

    var seconds = date.getUTCSeconds().toString();
    seconds = seconds.length === 1 ? "0"+seconds : seconds;

    var milliseconds = date.getUTCMilliseconds().toString();
    if(milliseconds.length === 1) milliseconds = "00"+milliseconds;
    if(milliseconds.length === 1) milliseconds = "0"+milliseconds;

    return year + "-" + month + "-" + day + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + "Z";
}

