if (typeof Wired == 'undefined') var Wired = {};

Wired.Date = function() {
    if (arguments.length > 1) arguments[1] -= 1;
    var args = [];
    for (var i = 0; i < arguments.length; i++) {
        args.push('arguments[' + i + ']');
    }
    this._date = eval('new Date(' + args.join(',') + ');');
};

Wired.Date.prototype = {
    toString: function() {
        return this.format('%F %T');
    },

    toUTCString: function() {
        return new Wired.Date(
            this.getUTCYear(), this.getUTCMonth(), this.getUTCDay(),
            this.getUTCHour(), this.getUTCMinute(), this.getUTCSecond()
        ).toString();
    },

    getMonth: function() {
        return this._date.getMonth() + 1;
    },

    setMonth: function(month) {
        return this._date.setMonth(month - 1);
    },

    getUTCMonth: function() {
        return this._date.getUTCMonth() + 1;
    },

    setUTCMonth: function(month) {
        return this._date.setUTCMonth(month - 1);
    },

    addYear: function(year) {
        this.setYear(this.getYear() + year);
        return this;
    },

    addMonth: function(month) {
        month = this._date.getMonth() + month;
        this.addYear(Math.floor(month / 12));
        this._date.setMonth((month % 12 + 12) % 12);
        return this;
    },

    addDay: function(day) {
        this.setDay(this.getDay() + day);
        return this;
    },

    addHour: function(hour) {
        this.setHour(this.getHour() + hour);
        return this;
    },

    addMinute: function(minute) {
        this.setMinute(this.getMinute() + minute);
        return this;
    },

    addSecond: function(second) {
        this.setSecond(this.getSecond() + second);
        return this;
    },

    addMillisecond: function(millisecond) {
        this.setMillisecond(this.getMillisecond() + millisecond);
        return this;
    },

    format: function(format) {
        var self = this;
        return format.replace(/%(.)/g, function() {
            switch (arguments[1]) {
            case 'C': return self.getYear().toString().slice(0, 2);
            case 'd': return ('0' + self.getDay()).slice(-2);
            case 'e': return (' ' + self.getDay()).slice(-2);
            case 'F': return self.format('%Y-%m-%d');
            case 'H': return ('0' + self.getHour()).slice(-2);
            case 'I': return ('0' + (self.getHour() % 12 == 0 ? 12 : self.getHour() % 12)).slice(-2);
            case 'k': return (' ' + self.getHour()).slice(-2);
            case 'l': return (' ' + (self.getHour() % 12 == 0 ? 12 : self.getHour() % 12)).slice(-2);
            case 'm': return ('0' + self.getMonth()).slice(-2);
            case 'M': return ('0' + self.getMinute()).slice(-2);
            case 'n': return '\n';
            case 'R': return self.format('%H:%M');
            case 's': return self.getTime();
            case 'S': return ('0' + self.getSecond()).slice(-2);
            case 'n': return '\t';
            case 'T': return self.format('%H:%M:%S');
            case 'u': return self.getWeekday() || 7;
            case 'w': return self.getWeekday();
            case 'y': return self.getYear().toString().slice(2, 4);
            case 'Y': return self.getYear();
            case '%': return '%';
            default:  return '%' + arguments[1];
            }
        });
    }
};

(function() {
    function delegate(self, property, method, alias) {
        if (arguments.length == 2) {
            alias = method;
        }
        if (alias == 'valueOf') {
            if (typeof self._wired_delegator_valueOf == 'undefined') {
                self._wired_delegator_valueOf = self.valueOf;
            }
            self[alias] = function() {
                return typeof this[property] == 'undefined'
                    ? this._wired_delegator_valueOf.apply(this, arguments)
                    : this[property][method].apply(this[property], arguments);
            };
        } else {
            self[alias] = function() {
                return this[property][method].apply(this[property], arguments);
            };
        }
    }

    var methods = [
        'getTime', 'getTimezoneOffset', 'setTime',
        'toLocaleString', 'toLocaleDateString', 'toLocaleTimeString',
        'toSource', 'valueOf'
    ];
    for (var i = 0; i < methods.length; i++) {
        delegate(Wired.Date.prototype, '_date', methods[i]);
    }

    var methods = {
        getDay:            'getDate',
        getWeekday:        'getDay',
        getYear:           'getFullYear',
        getHour:           'getHours',
        getMillisecond:    'getMilliseconds',
        getMinute:         'getMinutes',
        getSecond:         'getSeconds',
        getUTCDay:         'getUTCDate',
        getUTCWeekday:     'getUTCDay',
        getUTCYear:        'getUTCFullYear',
        getUTCHour:        'getUTCHours',
        getUTCMillisecond: 'getUTCMilliseconds',
        getUTCMinute:      'getUTCMinutes',
        getUTCSecond:      'getUTCSeconds',
        setDay:            'setDate',
        setYear:           'setFullYear',
        setHour:           'setHours',
        setMillisecond:    'setMilliseconds',
        setMinute:         'setMinutes',
        setSecond:         'setSeconds',
        setUTCDay:         'setUTCDate',
        setUTCYear:        'setUTCFullYear',
        setUTCHour:        'setUTCHours',
        setUTCMillisecond: 'setUTCMilliseconds',
        setUTCMinute:      'setUTCMinutes',
        setUTCSecond:      'setUTCSeconds'
    };
    for (var alias in methods) {
        delegate(Wired.Date.prototype, '_date', methods[alias], alias);
    }
})();

