(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define(["exports"], factory);
  } else if (typeof exports !== "undefined") {
    factory(exports);
  } else {
    var mod = {
      exports: {}
    };
    factory(mod.exports);
    global.WorkerPool = mod.exports;
  }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports) {
  "use strict";

  Object.defineProperty(_exports, "__esModule", {
    value: true
  });
  _exports.WorkerPool = void 0;

  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

  /**
   * @author Deepkolos / https://github.com/deepkolos
   */
  var WorkerPool = /*#__PURE__*/function () {
    function WorkerPool() {
      var pool = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 4;

      _classCallCheck(this, WorkerPool);

      this.pool = pool;
      this.queue = [];
      this.workers = [];
      this.workersResolve = [];
      this.workerStatus = 0;
    }

    _createClass(WorkerPool, [{
      key: "_initWorker",
      value: function _initWorker(workerId) {
        if (!this.workers[workerId]) {
          var worker = this.workerCreator();
          worker.addEventListener('message', this._onMessage.bind(this, workerId));
          this.workers[workerId] = worker;
        }
      }
    }, {
      key: "_getIdleWorker",
      value: function _getIdleWorker() {
        for (var i = 0; i < this.pool; i++) {
          if (!(this.workerStatus & 1 << i)) return i;
        }

        return -1;
      }
    }, {
      key: "_onMessage",
      value: function _onMessage(workerId, msg) {
        var resolve = this.workersResolve[workerId];
        resolve && resolve(msg);

        if (this.queue.length) {
          var _this$queue$shift = this.queue.shift(),
              _resolve = _this$queue$shift.resolve,
              _msg = _this$queue$shift.msg,
              transfer = _this$queue$shift.transfer;

          this.workersResolve[workerId] = _resolve;
          this.workers[workerId].postMessage(_msg, transfer);
        } else {
          this.workerStatus ^= 1 << workerId;
        }
      }
    }, {
      key: "setWorkerCreator",
      value: function setWorkerCreator(workerCreator) {
        this.workerCreator = workerCreator;
      }
    }, {
      key: "setWorkerLimit",
      value: function setWorkerLimit(pool) {
        this.pool = pool;
      }
    }, {
      key: "postMessage",
      value: function postMessage(msg, transfer) {
        var _this = this;

        return new Promise(function (resolve) {
          var workerId = _this._getIdleWorker();

          if (workerId !== -1) {
            _this._initWorker(workerId);

            _this.workerStatus |= 1 << workerId;
            _this.workersResolve[workerId] = resolve;

            _this.workers[workerId].postMessage(msg, transfer);
          } else {
            _this.queue.push({
              resolve: resolve,
              msg: msg,
              transfer: transfer
            });
          }
        });
      }
    }, {
      key: "dispose",
      value: function dispose() {
        this.workers.forEach(function (worker) {
          return worker.terminate();
        });
        this.workersResolve.length = 0;
        this.workers.length = 0;
        this.queue.length = 0;
        this.workerStatus = 0;
      }
    }]);

    return WorkerPool;
  }();

  _exports.WorkerPool = WorkerPool;
});