var Q = require('q'),
_ = require('underscore')._;
/**
* Promises/A+ spec compliant class, with a little extension
* http://promises-aplus.github.io/promises-spec/
*
* @class Promise
* @constructor
* @param {Promise.<T>|T} o - Object to wrap with promise
* @template T
*/
var Promise = function(o) {
this._promise = Q(o);
};
/**
* @callback FulfilledCallback
* @param {T} result - Fulfilled value
* @returns {S}
* @template T,S
*/
/**
* @callback RejectedCallback
* @param {Error} reason - Rejected reason
* @returns {S}
* @template S
*/
/**
* The "then" method from the Promises/A+ specification
*
* @param {FulfilledCallback.<T, S1>} [onFulfilled]
* @param {RejectedCallback.<S2>} [onRejected]
* @returns {Promise.<S1|S2>}
*/
Promise.prototype.then = function() {
// Delegate Q promise implementation and wrap by our Promise instance
return new Promise(this._promise.then.apply(this._promise, arguments));
};
/**
* Call "then" using given node-style callback function
*
* @param {Callback.<T>} [callback] - Callback function
* @returns {Promise.<T>}
*/
Promise.prototype.thenCall = function(callback) {
return _.isFunction(callback) ? this.then(function(res) {
return callback(null, res);
}, function(err) {
return callback(err);
}) : this;
};
/**
* A sugar method, equivalent to promise.then(undefined, onRejected).
*
* @param {RejectedCallback.<S>} onRejected
* @returns {Promise.<S>}
*/
Promise.prototype.fail = function() {
return new Promise(this._promise.fail.apply(this._promise, arguments));
};
/**
* Alias for completion
*
* @param {FulfilledCallback.<T, S>} [onFulfilled]
* @returns {Promise.<S>}
*/
Promise.prototype.done = function() {
return new Promise(this._promise.done.apply(this._promise, arguments));
};
/**
* @param {...Promise.<*>} p
*/
Promise.when = function() {
return new Promise(Q.when.apply(Q, arguments));
};
/**
* Returns rejecting promise with given reason
*
* @param {Error} reason - Rejecting reason
* @returns {Promise}
*/
Promise.reject = function(reason) {
return new Promise(Q.reject(reason));
};
/**
* Returns a promise that is fulfilled with an array containing the fulfillment value of each promise,
* or is rejected with the same rejection reason as the first promise to be rejected.
*
* @param {Array.<Promise.<*>|*>} promises
* @returns {Promise.<Array.<*>>}
*/
Promise.all = function() {
return new Promise(Q.all.apply(Q, arguments));
};
/**
* Returns a deferred object
*
* @returns {Deferred}
*/
Promise.defer = function() {
return new Deferred();
};
/**
* Deferred object
*
* @protected
* @constructor
*/
var Deferred = function() {
this._deferred = Q.defer();
this.promise = new Promise(this._deferred.promise);
};
/**
* Resolve promise
* @param {*} result - Resolving result
*/
Deferred.prototype.resolve = function() {
return this._deferred.resolve.apply(this._promise, arguments);
};
/**
* Reject promise
* @param {Error} error - Rejecting reason
*/
Deferred.prototype.reject = function() {
return this._deferred.reject.apply(this._promise, arguments);
};
/**
*
*/
module.exports = Promise;