(function() {
  var Promise, _, cp, getProfilePath, getShell, getShellObj, profiles, shell, sourced;

  _ = require("lodash");

  Promise = require("bluebird");

  cp = require("./util/child_process");

  profiles = {
    "~/.profile": /\/sh$/,
    "~/.bash_profile": /\/bash$/,
    "~/.cshrc": /\/csh$/,
    "~/.profile": /\/ksh$/,
    "~/.zshrc": /\/zsh$/,
    "~/.config/fish/config.fish": /\/fish$/
  };

  sourced = false;

  shell = null;

  getProfilePath = function(shellPath) {
    var profilePath, regex;
    for (profilePath in profiles) {
      regex = profiles[profilePath];
      if (regex.test(shellPath)) {
        return profilePath;
      }
    }
  };

  getShellObj = function(pathToShell) {
    pathToShell = _.trim(pathToShell);
    shell = {
      shellPath: pathToShell,
      profilePath: getProfilePath(pathToShell)
    };
    return Promise.resolve(shell);
  };

  getShell = function() {
    var s;
    if (shell) {
      return Promise.resolve(shell);
    }
    if (!(s = process.env.SHELL)) {
      return cp.execAsync("which bash").then(getShellObj)["catch"](function() {
        return getShellObj("");
      });
    } else {
      return getShellObj(s);
    }
  };

  module.exports = {
    reset: function() {
      return shell = null;
    },
    run: function(projectRoot, options) {
      var child, run;
      child = null;
      run = function() {
        return getShell().then(function(shell) {
          return new Promise(function(resolve, reject) {
            var cmd, output, ref;
            cmd = shell.profilePath && !sourced ? (sourced = true, "source " + shell.profilePath + " > /dev/null 2>&1; " + options.cmd) : options.cmd;
            child = cp.spawn(cmd, {
              cwd: projectRoot,
              env: _.extend({}, process.env, options.env),
              shell: (ref = shell.shellPath) != null ? ref : true
            });
            output = {
              shell: shell,
              stdout: "",
              stderr: ""
            };
            child.stdout.on("data", function(data) {
              return output.stdout += data.toString();
            });
            child.stderr.on("data", function(data) {
              return output.stderr += data.toString();
            });
            child.on("error", function(err) {
              return reject(err);
            });
            return child.on("close", function(code) {
              output.code = code;
              return resolve(output);
            });
          });
        });
      };
      return Promise["try"](run).timeout(options.timeout)["catch"](Promise.TimeoutError, function() {
        var err;
        if (child) {
          child.kill();
        }
        err = new Error("Process timed out");
        err.timedout = true;
        throw err;
      });
    }
  };

}).call(this);
