/**
 * Wrapper to manage services via PM2
 */
var _ = require('lodash');
var path = require('path');
var pm2 = require('pm2');
var semver = require('semver');
require('colors');

function Runner() {

}

Runner.prototype.init = function(bosco, next) {
	this.bosco = bosco;
	pm2.connect(next);
}

Runner.prototype.disconnect = function(next) {
    pm2.disconnect(next);
}

/**
 * List running services
 */
Runner.prototype.listRunning = function(detailed, next) {
	pm2.list(function(err, list) {
		var filteredList = _.filter(list, function(pm2Process){ return pm2Process.pm2_env.status === 'online' || pm2Process.pm2_env.status === 'errored' })

		if(!detailed) return next(err, _.pluck(filteredList,'name'));
		next(err, filteredList);
	});
}

/**
 * List services that have been created but are not running
 */
Runner.prototype.listNotRunning = function(detailed, next) {
	pm2.list(function(err, list) {
		var filteredList = _.filter(list, function(pm2Process){ return pm2Process.pm2_env.status !== 'online' })

		if(!detailed) return next(err, _.pluck(filteredList,'name'));
		next(err, filteredList);
	});
}

/**
 * Start a specific service
 * options = {cmd, cwd, name}
 */
Runner.prototype.start = function(options, next) {

	var self = this;

	// Remove node from the start script as not req'd for PM2
	var startCmd = options.service.start, startArr, start, ext;

	if(startCmd.split(' ')[0] == 'node') {
		startArr = startCmd.split(' ');
		startArr.shift();
		start = startArr.join(' ');

		ext = path.extname(startCmd);

		if(!path.extname(start)) {
			ext = '.js';
			start = start + '.js';
		}
	} else {
		start = startCmd;
	}

  // Always execute as a forked process to allow node version selection
	var executeCommand = true;

  // If the command has a -- in it then we know it is passing parameters
  // to pm2
  var argumentPos = start.indexOf(' -- ');
  var location = start;
  var scriptArgs = [];
  if (argumentPos > -1) {
    scriptArgs = start.substring(argumentPos + 4, start.length).split(' ');
    location = start.substring(0, argumentPos);
  }

	if(!self.bosco.exists(options.cwd + '/' + location)) {
		self.bosco.warn('Can\'t start ' + options.name.red + ', as I can\'t find script: ' + location.red);
		return next();
	}

  var startOptions = { name: options.name, cwd: options.cwd, watch: options.watch, executeCommand: executeCommand, force: true, scriptArgs: scriptArgs };

  var interpreter = getInterpreter(this.bosco, options.service);
  if(interpreter) {
    if(!self.bosco.exists(interpreter)) {
      self.bosco.warn('Unable to locate node version requested: ' + interpreter.cyan + '.  Reverting to default.');
    } else {
      startOptions.interpreter = interpreter;
      self.bosco.log('Starting ' + options.name.cyan + ' via ' + interpreter + ' ...');
    }
  } else {
    self.bosco.log('Starting ' + options.name.cyan + ' via ...');
  }

	pm2.start(location, startOptions, next);

}

/**
 * List running services
 */
Runner.prototype.stop = function(options, next) {
    var self = this;
	self.bosco.log('Stopping ' + options.name.cyan);
	pm2.stop(options.name, function(err) {
        if(err) return next(err);
 		pm2.delete(options.name, function(err) {
		  next(err);
		});
	});
}

function getInterpreter(bosco, service) {

  if(!service.nodeVersion) {
    return;
  }

  var homeFolder = bosco.findHomeFolder(), nvmNodePath;

  if(semver.gte(service.nodeVersion, '1.0.0')) {
    nvmNodePath = path.join('/.nvm/versions/io.js/','v' + service.nodeVersion,'/bin/node');
  } else if(semver.gte(service.nodeVersion, '0.12.0')) {
    nvmNodePath = path.join('/.nvm/versions/node/','v' + service.nodeVersion,'/bin/node');
  } else {
    nvmNodePath = path.join('/.nvm/','v' + service.nodeVersion,'/bin/node');
  }

  return path.join(homeFolder, nvmNodePath);

}

module.exports = new Runner();

@@ -3265,20 +3265,43 @@
 e) %7B%0A%0A  
-if(!
+var version = semver.parse(
 service.
@@ -3312,16 +3312,34 @@
 Version)
+;%0A%0A  if (!version)
  %7B%0A    r
@@ -3343,16 +3343,19 @@
   return
+ ''
 ;%0A  %7D%0A%0A 
@@ -3398,398 +3398,220 @@
 er()
-, nvmNodePath;%0A%0A  if(semver.gte(service.nodeVersion, '1.0.0')) %7B%0A    nvmNodePath = path.join('/.nvm/versions/io.js/','v' + service.nodeVersion,'/bin/
+;%0A  var nvmBase = '.nvm';%0A  var runtime = '
 node'
-)
 ;%0A
-  %7D else if(semver.gte(service.nodeVersion, '0.12.0')) %7B%0A    nvmNodePath = path.join('/.nvm/versions/node/','v' + service.nodeVersion,'/bin/node');%0A  %7D else %7B%0A    nvmNodePath = path.join('/.nvm/','v' + service.nodeVersion,'/bin/node'
+%0A  if (version.major %3E= 1) %7B%0A    runtime = 'io.js';%0A  %7D%0A%0A  if (runtime === 'io.js' %7C%7C version.minor %3E= 12) %7B %0A    nvmBase = path.join(nvmBase, 'versions', runtime
 );%0A 
@@ -3652,16 +3652,42 @@
  nvm
-NodePath
+Base, 'v' + version, 'bin', 'node'
 );%0A%0A

improve readability of getInterpreter function