'use strict';

const utils = require('../utils'); const Context = require('../context'); const Mocha = require('../mocha'); const collectFiles = require('./collect-files');

/**

* Exports the `watchRun` function that runs mocha in "watch" mode.
* @see module:lib/cli/run-helpers
* @module
* @private
*/

/**

* Run Mocha in "watch" mode
* @param {Mocha} mocha - Mocha instance
* @param {Object} opts - Options
* @param {string} opts.ui - User interface
* @param {Object} fileCollectParams - Parameters that control test
*   file collection. See `lib/cli/collect-files.js`.
* @param {string[]} fileCollectParams.extension - List of extensions to watch
* @private
*/

module.exports = (mocha, {ui}, fileCollectParams) => {

let runner;
const files = collectFiles(fileCollectParams);

console.log();
hideCursor();
process.on('SIGINT', () => {
  showCursor();
  console.log('\n');
  // By UNIX/Posix convention this indicates that the process was
  // killed by SIGINT which has portable number 2.
  process.exit(128 + 2);
});

const watchFiles = utils.files(process.cwd(), fileCollectParams.extension);
let runAgain = false;

const loadAndRun = () => {
  try {
    mocha.files = files;
    runAgain = false;
    runner = mocha.run(() => {
      runner = null;
      if (runAgain) {
        rerun();
      }
    });
  } catch (e) {
    console.log(e.stack);
  }
};

const purge = () => {
  watchFiles.forEach(Mocha.unloadFile);
};

loadAndRun();

const rerun = () => {
  purge();
  eraseLine();
  mocha.suite = mocha.suite.clone();
  mocha.suite.ctx = new Context();
  mocha.ui(ui);
  loadAndRun();
};

utils.watch(watchFiles, () => {
  runAgain = true;
  if (runner) {
    runner.abort();
  } else {
    rerun();
  }
});

};

/**

* Hide the cursor.
* @ignore
* @private
*/

const hideCursor = () => {

process.stdout.write('\u001b[?25l');

};

/**

* Show the cursor.
* @ignore
* @private
*/

const showCursor = () => {

process.stdout.write('\u001b[?25h');

};

/**

* Erases the line on stdout
* @private
*/

const eraseLine = () => {

process.stdout.write('\u001b[2K');

};