(function() {
  var ChunkedExecutor, MAX_CONCURRENT_CHUNK,
    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  MAX_CONCURRENT_CHUNK = 20;

  module.exports = ChunkedExecutor = (function() {
    function ChunkedExecutor(pathQueue, execPathFn) {
      var p;
      this.execPathFn = execPathFn;
      this.push = bind(this.push, this);
      this.pathQueue = (function() {
        var j, len, results;
        results = [];
        for (j = 0, len = pathQueue.length; j < len; j++) {
          p = pathQueue[j];
          results.push(p);
        }
        return results;
      })();
      this.pathCount = pathQueue.length;
      this.pathsRunning = 0;
    }


    /*
    Section: Execution
     */

    ChunkedExecutor.prototype.execute = function(doneCallback) {
      var i, j, ref;
      this.doneCallback = doneCallback;
      for (i = j = 0, ref = MAX_CONCURRENT_CHUNK; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
        this.executeNextPathIfPossible();
      }
    };

    ChunkedExecutor.prototype.push = function(filePath) {
      this.pathCount++;
      if (this.pathsRunning < MAX_CONCURRENT_CHUNK) {
        return this.executePath(filePath);
      } else {
        return this.pathQueue.push(filePath);
      }
    };


    /*
    Section: Lifecycle Methods
     */

    ChunkedExecutor.prototype.executeNextPathIfPossible = function() {
      if (this.pathsRunning < MAX_CONCURRENT_CHUNK && this.pathQueue.length) {
        return this.executePath(this.pathQueue.shift());
      }
    };

    ChunkedExecutor.prototype.executePath = function(filePath) {
      this.pathsRunning++;
      return this.execPathFn(filePath, (function(_this) {
        return function() {
          _this.pathCount--;
          _this.pathsRunning--;
          return _this.checkIfFinished();
        };
      })(this));
    };

    ChunkedExecutor.prototype.checkIfFinished = function() {
      this.executeNextPathIfPossible();
      if (this.pathCount === 0) {
        return this.doneCallback();
      }
    };

    return ChunkedExecutor;

  })();

}).call(this);
