text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
      value: true
  });
  exports.default = queue;
  
  var _baseIndexOf = require('lodash/_baseIndexOf');
  
  var _baseIndexOf2 = _interopRequireDefault(_baseIndexOf);
  
  var _isArray = require('lodash/isArray');
  
  var _isArray2 = _interopRequireDefault(_isArray);
  
  var _noop = require('lodash/noop');
  
  var _noop2 = _interopRequireDefault(_noop);
  
  var _onlyOnce = require('./onlyOnce');
  
  var _onlyOnce2 = _interopRequireDefault(_onlyOnce);
  
  var _setImmediate = require('./setImmediate');
  
  var _setImmediate2 = _interopRequireDefault(_setImmediate);
  
  var _DoublyLinkedList = require('./DoublyLinkedList');
  
  var _DoublyLinkedList2 = _interopRequireDefault(_DoublyLinkedList);
  
  var _wrapAsync = require('./wrapAsync');
  
  var _wrapAsync2 = _interopRequireDefault(_wrapAsync);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function queue(worker, concurrency, payload) {
      if (concurrency == null) {
          concurrency = 1;
      } else if (concurrency === 0) {
          throw new Error('Concurrency must not be zero');
      }
  
      var _worker = (0, _wrapAsync2.default)(worker);
      var numRunning = 0;
      var workersList = [];
  
      var processingScheduled = false;
      function _insert(data, insertAtFront, callback) {
          if (callback != null && typeof callback !== 'function') {
              throw new Error('task callback must be a function');
          }
          q.started = true;
          if (!(0, _isArray2.default)(data)) {
              data = [data];
          }
          if (data.length === 0 && q.idle()) {
              // call drain immediately if there are no tasks
              return (0, _setImmediate2.default)(function () {
                  q.drain();
              });
          }
  
          for (var i = 0, l = data.length; i < l; i++) {
              var item = {
                  data: data[i],
                  callback: callback || _noop2.default
              };
  
              if (insertAtFront) {
                  q._tasks.unshift(item);
              } else {
                  q._tasks.push(item);
              }
          }
  
          if (!processingScheduled) {
              processingScheduled = true;
              (0, _setImmediate2.default)(function () {
                  processingScheduled = false;
                  q.process();
              });
          }
      }
  
      function _next(tasks) {
          return function (err) {
              numRunning -= 1;
  
              for (var i = 0, l = tasks.length; i < l; i++) {
                  var task = tasks[i];
  
                  var index = (0, _baseIndexOf2.default)(workersList, task, 0);
                  if (index === 0) {
                      workersList.shift();
                  } else if (index > 0) {
                      workersList.splice(index, 1);
                  }
  
                  task.callback.apply(task, arguments);
  
                  if (err != null) {
                      q.error(err, task.data);
                  }
              }
  
              if (numRunning <= q.concurrency - q.buffer) {
                  q.unsaturated();
              }
  
              if (q.idle()) {
                  q.drain();
              }
              q.process();
          };
      }
  
      var isProcessing = false;
      var q = {
          _tasks: new _DoublyLinkedList2.default(),
          concurrency: concurrency,
          payload: payload,
          saturated: _noop2.default,
          unsaturated: _noop2.default,
          buffer: concurrency / 4,
          empty: _noop2.default,
          drain: _noop2.default,
          error: _noop2.default,
          started: false,
          paused: false,
          push: function (data, callback) {
              _insert(data, false, callback);
          },
          kill: function () {
              q.drain = _noop2.default;
              q._tasks.empty();
          },
          unshift: function (data, callback) {
              _insert(data, true, callback);
          },
          remove: function (testFn) {
              q._tasks.remove(testFn);
          },
          process: function () {
              // Avoid trying to start too many processing operations. This can occur
              // when callbacks resolve synchronously (#1267).
              if (isProcessing) {
                  return;
              }
              isProcessing = true;
              while (!q.paused && numRunning < q.concurrency && q._tasks.length) {
                  var tasks = [],
                      data = [];
                  var l = q._tasks.length;
                  if (q.payload) l = Math.min(l, q.payload);
                  for (var i = 0; i < l; i++) {
                      var node = q._tasks.shift();
                      tasks.push(node);
                      workersList.push(node);
                      data.push(node.data);
                  }
  
                  numRunning += 1;
  
                  if (q._tasks.length === 0) {
                      q.empty();
                  }
  
                  if (numRunning === q.concurrency) {
                      q.saturated();
                  }
  
                  var cb = (0, _onlyOnce2.default)(_next(tasks));
                  _worker(data, cb);
              }
              isProcessing = false;
          },
          length: function () {
              return q._tasks.length;
          },
          running: function () {
              return numRunning;
          },
          workersList: function () {
              return workersList;
          },
          idle: function () {
              return q._tasks.length + numRunning === 0;
          },
          pause: function () {
              q.paused = true;
          },
          resume: function () {
              if (q.paused === false) {
                  return;
              }
              q.paused = false;
              (0, _setImmediate2.default)(q.process);
          }
      };
      return q;
  }
  module.exports = exports['default'];
  