text: import {
      isFunction
  } from './utils';
  
  import {
      noop,
      subscribe,
      initializePromise,
      invokeCallback,
      FULFILLED,
      REJECTED
  } from './-internal';
  
  import asap from './asap';
  
  import all from './promise/all';
  import race from './promise/race';
  import Resolve from './promise/resolve';
  import Reject from './promise/reject';
  
  var counter = 0;
  
  function needsResolver() {
      throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
  }
  
  function needsNew() {
      throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
  }
  
  export default Promise;
  /**
   Promise objects represent the eventual result of an asynchronous operation. The
   primary way of interacting with a promise is through its `then` method, which
   registers callbacks to receive either a promise’s eventual value or the reason
   why the promise cannot be fulfilled.
  
   Terminology
   -----------
  
   - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
   - `thenable` is an object or function that defines a `then` method.
   - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
   - `exception` is a value that is thrown using the throw statement.
   - `reason` is a value that indicates why a promise was rejected.
   - `settled` the final resting state of a promise, fulfilled or rejected.
  
   A promise can be in one of three states: pending, fulfilled, or rejected.
  
   Promises that are fulfilled have a fulfillment value and are in the fulfilled
   state.  Promises that are rejected have a rejection reason and are in the
   rejected state.  A fulfillment value is never a thenable.
  
   Promises can also be said to *resolve* a value.  If this value is also a
   promise, then the original promise's settled state will match the value's
   settled state.  So a promise that *resolves* a promise that rejects will
   itself reject, and a promise that *resolves* a promise that fulfills will
   itself fulfill.
  
  
   Basic Usage:
   ------------
  
   ```js
   var promise = new Promise(function(resolve, reject) {
      // on success
      resolve(value);
  
      // on failure
      reject(reason);
    });
  
   promise.then(function(value) {
      // on fulfillment
    }, function(reason) {
      // on rejection
    });
   ```
  
   Advanced Usage:
   ---------------
  
   Promises shine when abstracting away asynchronous interactions such as
   `XMLHttpRequest`s.
  
   ```js
   function getJSON(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
  
        xhr.open('GET', url);
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.send();
  
        function handler() {
          if (this.readyState === this.DONE) {
            if (this.status === 200) {
              resolve(this.response);
            } else {
              reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
            }
          }
        };
      });
    }
  
   getJSON('/posts.json').then(function(json) {
      // on fulfillment
    }, function(reason) {
      // on rejection
    });
   ```
  
   Unlike callbacks, promises are great composable primitives.
  
   ```js
   Promise.all([
   getJSON('/posts'),
   getJSON('/comments')
   ]).then(function(values){
      values[0] // => postsJSON
      values[1] // => commentsJSON
  
      return values;
    });
   ```
  
   @class Promise
   @param {function} resolver
   Useful for tooling.
   @constructor
   */
  function Promise(resolver) {
      this._id = counter++;
      this._state = undefined;
      this._result = undefined;
      this._subscribers = [];
  
      if (noop !== resolver) {
          if (!isFunction(resolver)) {
              needsResolver();
          }
  
          if (!(this instanceof Promise)) {
              needsNew();
          }
  
          initializePromise(this, resolver);
      }
  }
  
  Promise.all = all;
  Promise.race = race;
  Promise.resolve = Resolve;
  Promise.reject = Reject;
  
  Promise.prototype = {
      constructor: Promise,
  
      /**
       The primary way of interacting with a promise is through its `then` method,
       which registers callbacks to receive either a promise's eventual value or the
       reason why the promise cannot be fulfilled.
  
       ```js
       findUser().then(function(user){
      // user is available
    }, function(reason){
      // user is unavailable, and you are given the reason why
    });
       ```
  
       Chaining
       --------
  
       The return value of `then` is itself a promise.  This second, 'downstream'
       promise is resolved with the return value of the first promise's fulfillment
       or rejection handler, or rejected if the handler throws an exception.
  
       ```js
       findUser().then(function (user) {
      return user.name;
    }, function (reason) {
      return 'default name';
    }).then(function (userName) {
      // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
      // will be `'default name'`
    });
  
       findUser().then(function (user) {
      throw new Error('Found user, but still unhappy');
    }, function (reason) {
      throw new Error('`findUser` rejected and we're unhappy');
    }).then(function (value) {
      // never reached
    }, function (reason) {
      // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
      // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
    });
       ```
       If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
  
       ```js
       findUser().then(function (user) {
      throw new PedagogicalException('Upstream error');
    }).then(function (value) {
      // never reached
    }).then(function (value) {
      // never reached
    }, function (reason) {
      // The `PedgagocialException` is propagated all the way down to here
    });
       ```
  
       Assimilation
       ------------
  
       Sometimes the value you want to propagate to a downstream promise can only be
       retrieved asynchronously. This can be achieved by returning a promise in the
       fulfillment or rejection handler. The downstream promise will then be pending
       until the returned promise is settled. This is called *assimilation*.
  
       ```js
       findUser().then(function (user) {
      return findCommentsByAuthor(user);
    }).then(function (comments) {
      // The user's comments are now available
    });
       ```
  
       If the assimliated promise rejects, then the downstream promise will also reject.
  
       ```js
       findUser().then(function (user) {
      return findCommentsByAuthor(user);
    }).then(function (comments) {
      // If `findCommentsByAuthor` fulfills, we'll have the value here
    }, function (reason) {
      // If `findCommentsByAuthor` rejects, we'll have the reason here
    });
       ```
  
       Simple Example
       --------------
  
       Synchronous Example
  
       ```javascript
       var result;
  
       try {
      result = findResult();
      // success
    } catch(reason) {
      // failure
    }
       ```
  
       Errback Example
  
       ```js
       findResult(function(result, err){
      if (err) {
        // failure
      } else {
        // success
      }
    });
       ```
  
       Promise Example;
  
       ```javascript
       findResult().then(function(result){
      // success
    }, function(reason){
      // failure
    });
       ```
  
       Advanced Example
       --------------
  
       Synchronous Example
  
       ```javascript
       var author, books;
  
       try {
      author = findAuthor();
      books  = findBooksByAuthor(author);
      // success
    } catch(reason) {
      // failure
    }
       ```
  
       Errback Example
  
       ```js
  
       function foundBooks(books) {
  
    }
  
       function failure(reason) {
  
    }
  
       findAuthor(function(author, err){
      if (err) {
        failure(err);
        // failure
      } else {
        try {
          findBoooksByAuthor(author, function(books, err) {
            if (err) {
              failure(err);
            } else {
              try {
                foundBooks(books);
              } catch(reason) {
                failure(reason);
              }
            }
          });
        } catch(error) {
          failure(err);
        }
        // success
      }
    });
       ```
  
       Promise Example;
  
       ```javascript
       findAuthor().
       then(findBooksByAuthor).
       then(function(books){
        // found books
    }).catch(function(reason){
      // something went wrong
    });
       ```
  
       @method then
       @param {Function} onFulfilled
       @param {Function} onRejected
       Useful for tooling.
       @return {Promise}
       */
      then: function (onFulfillment, onRejection) {
          var parent = this;
          var state = parent._state;
  
          if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) {
              return this;
          }
  
          var child = new this.constructor(noop);
          var result = parent._result;
  
          if (state) {
              var callback = arguments[state - 1];
              asap(function () {
                  invokeCallback(state, child, callback, result);
              });
          } else {
              subscribe(parent, child, onFulfillment, onRejection);
          }
  
          return child;
      },
  
      /**
       `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
       as the catch block of a try/catch statement.
  
       ```js
       function findAuthor(){
      throw new Error('couldn't find that author');
    }
  
       // synchronous
       try {
      findAuthor();
    } catch(reason) {
      // something went wrong
    }
  
       // async with promises
       findAuthor().catch(function(reason){
      // something went wrong
    });
       ```
  
       @method catch
       @param {Function} onRejection
       Useful for tooling.
       @return {Promise}
       */
      'catch': function (onRejection) {
          return this.then(null, onRejection);
      }
  };
  