'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _child_process = require('child_process');

var _child_process2 = _interopRequireDefault(_child_process);

var _command_types = require('./command_types');

var _command_types2 = _interopRequireDefault(_command_types);

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _readline = require('readline');

var _readline2 = _interopRequireDefault(_readline);

var _status = require('../../status');

var _status2 = _interopRequireDefault(_status);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var slaveCommand = _path2.default.resolve(__dirname, '..', '..', '..', 'bin', 'run_slave');

var Master = function () {
  // options - {dryRun, failFast, filterStacktraces, strict}
  function Master(_ref) {
    var eventBroadcaster = _ref.eventBroadcaster,
        options = _ref.options,
        supportCodePaths = _ref.supportCodePaths,
        supportCodeRequiredModules = _ref.supportCodeRequiredModules,
        testCases = _ref.testCases;
    (0, _classCallCheck3.default)(this, Master);

    this.eventBroadcaster = eventBroadcaster;
    this.options = options || {};
    this.supportCodePaths = supportCodePaths;
    this.supportCodeRequiredModules = supportCodeRequiredModules;
    this.testCases = testCases || [];
    this.nextTestCaseIndex = 0;
    this.testCasesCompleted = 0;
    this.result = {
      duration: 0,
      success: true
    };
    this.slaves = {};
  }

  (0, _createClass3.default)(Master, [{
    key: 'parseSlaveLine',
    value: function parseSlaveLine(slave, line) {
      var input = JSON.parse(line);
      switch (input.command) {
        case _command_types2.default.READY:
          this.giveSlaveWork(slave);
          break;
        case _command_types2.default.EVENT:
          this.eventBroadcaster.emit(input.name, input.data);
          if (input.name === 'test-case-finished') {
            this.parseTestCaseResult(input.data.result);
          }
          break;
        default:
          throw new Error('Unexpected message from slave: ' + line);
      }
    }
  }, {
    key: 'startSlave',
    value: function startSlave(id, total) {
      var _this = this;

      var slaveProcess = _child_process2.default.spawn(slaveCommand, [], {
        env: _lodash2.default.assign({}, process.env, {
          CUCUMBER_PARALLEL: 'true',
          CUCUMBER_TOTAL_SLAVES: total,
          CUCUMBER_SLAVE_ID: id
        }),
        stdio: ['pipe', 'pipe', process.stderr]
      });
      var rl = _readline2.default.createInterface({ input: slaveProcess.stdout });
      var slave = { process: slaveProcess };
      this.slaves[id] = slave;
      rl.on('line', function (line) {
        _this.parseSlaveLine(slave, line);
      });
      rl.on('close', function () {
        slave.closed = true;
        _this.onSlaveClose();
      });
      slave.process.stdin.write(JSON.stringify({
        command: _command_types2.default.INITIALIZE,
        filterStacktraces: this.options.filterStacktraces,
        supportCodePaths: this.supportCodePaths,
        supportCodeRequiredModules: this.supportCodeRequiredModules,
        worldParameters: this.options.worldParameters
      }) + '\n');
    }
  }, {
    key: 'onSlaveClose',
    value: function onSlaveClose() {
      if (_lodash2.default.every(this.slaves, 'closed')) {
        this.eventBroadcaster.emit('test-run-finished', { result: this.result });
        this.onFinish(this.result.success);
      }
    }
  }, {
    key: 'parseTestCaseResult',
    value: function parseTestCaseResult(testCaseResult) {
      this.testCasesCompleted += 1;
      if (testCaseResult.duration) {
        this.result.duration += testCaseResult.duration;
      }
      if (this.shouldCauseFailure(testCaseResult.status)) {
        this.result.success = false;
      }
    }
  }, {
    key: 'run',
    value: function run(numberOfSlaves, done) {
      var _this2 = this;

      this.eventBroadcaster.emit('test-run-started');
      _lodash2.default.times(numberOfSlaves, function (id) {
        return _this2.startSlave(id, numberOfSlaves);
      });
      this.onFinish = done;
    }
  }, {
    key: 'giveSlaveWork',
    value: function giveSlaveWork(slave) {
      if (this.nextTestCaseIndex === this.testCases.length) {
        slave.process.stdin.write(JSON.stringify({ command: _command_types2.default.FINALIZE }) + '\n');
        return;
      }
      var testCase = this.testCases[this.nextTestCaseIndex];
      this.nextTestCaseIndex += 1;
      var skip = this.options.dryRun || this.options.failFast && !this.result.success;
      slave.process.stdin.write(JSON.stringify({ command: _command_types2.default.RUN, skip: skip, testCase: testCase }) + '\n');
    }
  }, {
    key: 'shouldCauseFailure',
    value: function shouldCauseFailure(status) {
      return _lodash2.default.includes([_status2.default.AMBIGUOUS, _status2.default.FAILED, _status2.default.UNDEFINED], status) || status === _status2.default.PENDING && this.options.strict;
    }
  }]);
  return Master;
}();

exports.default = Master;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 10848 characters]