text: import {
    isArray,
    isMaybeThenable
  } from './utils';
  import {
    noop,
    reject,
    fulfill,
    subscribe,
    FULFILLED,
    REJECTED,
    PENDING,
    handleMaybeThenable
  } from './-internal';
  
  import then from './then';
  import Promise from './promise';
  import originalResolve from './promise/resolve';
  import originalThen from './then';
  import { makePromise, PROMISE_ID } from './-internal';
  
  function validationError() {
    return new Error('Array Methods must be provided an Array');
  };
  
  export default class Enumerator {
    constructor(Constructor, input) {
      this._instanceConstructor = Constructor;
      this.promise = new Constructor(noop);
  
      if (!this.promise[PROMISE_ID]) {
        makePromise(this.promise);
      }
  
      if (isArray(input)) {
        this.length     = input.length;
        this._remaining = input.length;
  
        this._result = new Array(this.length);
  
        if (this.length === 0) {
          fulfill(this.promise, this._result);
        } else {
          this.length = this.length || 0;
          this._enumerate(input);
          if (this._remaining === 0) {
            fulfill(this.promise, this._result);
          }
        }
      } else {
        reject(this.promise, validationError());
      }
    }
    _enumerate(input) {
      for (let i = 0; this._state === PENDING && i < input.length; i++) {
        this._eachEntry(input[i], i);
      }
    }
  
    _eachEntry(entry, i) {
      let c = this._instanceConstructor;
      let { resolve } = c;
  
      if (resolve === originalResolve) {
        let then;
        let error;
        let didError = false;
        try {
          then = entry.then;
        } catch (e) {
          didError = true;
          error = e;
        }
  
        if (then === originalThen &&
          entry._state !== PENDING) {
          this._settledAt(entry._state, i, entry._result);
        } else if (typeof then !== 'function') {
          this._remaining--;
          this._result[i] = entry;
        } else if (c === Promise) {
          let promise = new c(noop);
          if (didError) {
            reject(promise, error);
          } else {
            handleMaybeThenable(promise, entry, then);
          }
          this._willSettleAt(promise, i);
        } else {
          this._willSettleAt(new c(resolve => resolve(entry)), i);
        }
      } else {
        this._willSettleAt(resolve(entry), i);
      }
    }
  
    _settledAt(state, i, value) {
      let { promise } = this;
  
      if (promise._state === PENDING) {
        this._remaining--;
  
        if (state === REJECTED) {
          reject(promise, value);
        } else {
          this._result[i] = value;
        }
      }
  
      if (this._remaining === 0) {
        fulfill(promise, this._result);
      }
    }
  
    _willSettleAt(promise, i) {
      let enumerator = this;
  
      subscribe(
        promise, undefined,
        value => enumerator._settledAt(FULFILLED, i, value),
        reason => enumerator._settledAt(REJECTED, i, reason)
      );
    }
  };
  