"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _isPromise = _interopRequireDefault(require("is-promise"));

var _utils = require("../data-set/utils");

function isPromiseCallback(task) {
  return typeof task === 'function';
}

var PromiseTask = /*#__PURE__*/function () {
  function PromiseTask(task) {
    (0, _classCallCheck2["default"])(this, PromiseTask);
    this[Symbol.toStringTag] = 'Promise';
    this.task = task;

    if ((0, _isPromise["default"])(task)) {
      this.promise = task;
    }
  }

  (0, _createClass2["default"])(PromiseTask, [{
    key: "run",
    value: function run() {
      var _this = this;

      var promise = this.promise;

      if (promise) {
        return promise;
      }

      var task = this.task;

      if (isPromiseCallback(task)) {
        var newPromise = task();
        this.promise = newPromise;
        var resolveCallbacks = this.resolveCallbacks,
            rejectCallbacks = this.rejectCallbacks;

        if (resolveCallbacks && resolveCallbacks.length) {
          newPromise.then(function (v) {
            resolveCallbacks.forEach(function (cb) {
              return cb(v);
            });
            delete _this.resolveCallbacks;
            return v;
          });
        }

        if (rejectCallbacks && rejectCallbacks.length) {
          newPromise["catch"](function (v) {
            rejectCallbacks.forEach(function (cb) {
              return cb(v);
            });
            delete _this.rejectCallbacks;
            throw v;
          });
        }

        return newPromise;
      }

      return task;
    }
  }, {
    key: "catch",
    value: function _catch(onrejected) {
      var _this2 = this;

      var promise = this.promise;

      if (promise) {
        return promise["catch"](onrejected && function (error) {
          return onrejected(error);
        });
      }

      return new Promise(function (_, reject) {
        var rejectCallbacks = (0, _utils.getIf)(_this2, 'rejectCallbacks', []);
        rejectCallbacks.push(function (v) {
          return reject(onrejected ? onrejected(v) : v);
        });
      });
    }
  }, {
    key: "then",
    value: function then(onfulfilled, onrejected) {
      var _this3 = this;

      var promise = this.promise;

      if (promise) {
        return promise.then(onfulfilled && function (value) {
          return onfulfilled(value);
        }, onrejected && function (error) {
          return onrejected(error);
        });
      }

      return new Promise(function (resolve, reject) {
        var resolveCallbacks = (0, _utils.getIf)(_this3, 'resolveCallbacks', []);
        var rejectCallbacks = (0, _utils.getIf)(_this3, 'rejectCallbacks', []);
        resolveCallbacks.push(function (v) {
          return resolve(onfulfilled ? onfulfilled(v) : v);
        });
        rejectCallbacks.push(function (v) {
          return reject(onrejected ? onrejected(v) : v);
        });
      });
    }
  }]);
  return PromiseTask;
}();

var PromiseQueue = /*#__PURE__*/function () {
  function PromiseQueue() {
    var _this4 = this;

    var threads = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
    (0, _classCallCheck2["default"])(this, PromiseQueue);
    this.queue = [];
    this.queueing = false;

    this.$nextTask = function () {
      var task = _this4.queue.shift();

      if (task) {
        return task.run().then(function () {
          if (_this4.queueing) {
            return _this4.$nextTask();
          }
        })["catch"](function (error) {
          _this4.stop();

          throw error;
        });
      }

      return Promise.resolve();
    };

    if (threads < 1) {
      throw new Error('The first argument of PromiseQueue constructor must be greater than 0.');
    }

    this.threads = threads;
  }

  (0, _createClass2["default"])(PromiseQueue, [{
    key: "$clear",
    value: function $clear(promise) {
      if (!this.queueing) {
        var queue = this.queue;
        var index = queue.indexOf(promise);

        if (index !== -1) {
          queue.splice(index, 1);
        }
      }
    }
  }, {
    key: "add",
    value: function add(promise) {
      var _this5 = this;

      var queue = this.queue;
      var task = new PromiseTask(promise);
      queue.push(task);
      return task.then(function (value) {
        _this5.$clear(task);

        return value;
      })["catch"](function (error) {
        _this5.$clear(task);

        throw error;
      });
    }
  }, {
    key: "stop",
    value: function stop() {
      this.queueing = false;
    }
  }, {
    key: "ready",
    value: function () {
      var _ready = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
        var _this6 = this;

        var queue, threads;
        return _regenerator["default"].wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                queue = this.queue, threads = this.threads;

                if (!queue.length) {
                  _context.next = 9;
                  break;
                }

                this.queueing = true;
                _context.prev = 3;
                _context.next = 6;
                return Promise.all(new Array(threads).fill(0).map(function () {
                  return _this6.$nextTask();
                }));

              case 6:
                _context.prev = 6;
                this.queueing = false;
                return _context.finish(6);

              case 9:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this, [[3,, 6, 9]]);
      }));

      function ready() {
        return _ready.apply(this, arguments);
      }

      return ready;
    }()
  }]);
  return PromiseQueue;
}();

exports["default"] = PromiseQueue;
//# sourceMappingURL=index.js.map
