#!/usr/bin/env node


/**
 * Module dependencies
 */

var nodepath = require('path');
var REPL = require('repl');
var fs = require('fs');
var _ = require('lodash');
var chalk = require('chalk');
var CaptainsLog = require('captains-log');
var Sails = require('../lib/app');
var rconf = require('../lib/app/configuration/rc');
var Err = require('../errors');
var package = require('../package.json');


/**
 * `sails console`
 *
 * Enter the interactive console (aka REPL) for the app
 * in our working directory.  This is just like the default
 * Node REPL except that it starts with the Sails app in the
 * current directory lifted, and with console history enabled
 * (i.e. so you can press up arrow to browse and potentially
 *  replay commands from past runs)
 *
 * @stability 3
 * @see http://sailsjs.org/documentation/reference/command-line-interface/sails-console
 * ------------------------------------------------------------------------
 * This lifts the Sails app in the current working directory, then uses
 * the `repl` package to spin up an interactive console.
 */

module.exports = function() {

  // Get a logger
  var log = CaptainsLog(rconf.log);

  // Build initial scope, mixing-in rc config
  var scope = _.merge({
    rootPath: process.cwd(),
    sailsPackageJSON: package
  }, rconf, {

    // Disable ASCII ship to keep from dirtying things up
    log: {
      noShip: true
    }
  });

  // Assume the current working directory to be the root of the app
  var appPath = process.cwd();

  // Determine whether to use the local or global Sails install
  var sailsToLift = (function(){
    // Use the app's local Sails in `node_modules` if it's extant and valid
    var localSailsPath = nodepath.resolve(appPath, 'node_modules/sails');
    if (Sails.isLocalSailsValid(localSailsPath, appPath)) {
      return require(localSailsPath);
    } else {
      // Otherwise, if no workable local Sails exists, run the app
      // using the currently running version of Sails.  This is
      // probably always the global install.
      log.info('No local Sails install detected; using globally-installed Sails.');
      return Sails();
    }
  })();

  console.log();
  log.info(chalk.blue('Starting app in interactive mode...'));
  console.log();

  // Lift Sails
  sailsToLift.lift(scope, function(err) {
    if (err) {
      return Err.fatal.failedToLoadSails(err);
    }

    log.info('Welcome to the Sails console.');
    log.info(chalk.grey('( to exit, type ' + '<CTRL>+<C>' + ' )'));
    console.log();

    // Start a REPL
    var repl = REPL.start({prompt: 'sails> ', useGlobal: true});
    try {
      history(repl, nodepath.join(sails.config.paths.tmp, '.node_history'));
    } catch (e) {
      log.verbose('Console history cannot be found.  Proceeding without it. This is due to error:', e);
    }
    repl.on('exit', function(err) {
      if (err) {
        log.error(err);
        process.exit(1);
      }
      process.exit(0);
    });

  });
};



/**
 * REPL History
 * Pulled directly from https://github.com/tmpvar/repl.history
 * with the slight tweak of setting historyIndex to -1 so that
 * it works as expected.
 */

function history(repl, file) {

  try {
    var stat = fs.statSync(file);
    repl.rli.history = fs.readFileSync(file, 'utf-8').split('\n').reverse();
    repl.rli.history.shift();
    repl.rli.historyIndex = -1;
  } catch (e) {}

  var fd = fs.openSync(file, 'a'),
    reval = repl.eval;

  repl.rli.addListener('line', function(code) {
    if (code && code !== '.history') {
      fs.write(fd, code + '\n');
    } else {
      repl.rli.historyIndex++;
      repl.rli.history.pop();
    }
  });

  process.on('exit', function() {
    fs.closeSync(fd);
  });

  repl.commands['.history'] = {
    help: 'Show the history',
    action: function() {
      var out = [];
      repl.rli.history.forEach(function(v, k) {
        out.push(v);
      });
      repl.outputStream.write(out.reverse().join('\n') + '\n');
      repl.displayPrompt();
    }
  };
}

@@ -394,16 +394,17 @@
 on');%0A%0A%0A
+%0A
 /**%0A * %60
@@ -1069,16 +1069,238 @@
 onsole.%0A
+ *%0A * Note that, if %60--dontLift%60 was set, then %60sails.load()%60 will be used%0A * instead. (By default, the %60sails console%60 cmd runs %60sails.lift()%60.)%0A * ------------------------------------------------------------------------%0A
  */%0A%0Amod
@@ -1790,16 +1790,17 @@
  install
+.
 %0A  var s
@@ -1803,22 +1803,19 @@
 ar sails
-ToLift
+App
  = (func
@@ -1818,16 +1818,54 @@
 function
+ _determineAppropriateSailsAppInstance
 ()%7B%0A    
@@ -2512,24 +2512,25 @@
 ole.log();%0A%0A
+%0A
   // Lift Sa
@@ -2531,54 +2531,339 @@
 ift 
-Sails%0A  sailsToLift.lift(scope, function
+(or load) Sails%0A  (function _ifThenFinally(done)%7B%0A    // If %60--dontLift%60 was set, then use %60.load()%60 instead.%0A    if (!_.isUndefined(scope.dontLift)) %7B%0A      sailsApp.load(scope, done);%0A    %7D%0A    // Otherwise, go with the default behavior (%60.lift()%60)%0A    else %7B%0A      sailsApp.lift(scope, done);%0A    %7D%0A  %7D)(function afterwards
 (err)
- 
 %7B%0A  
@@ -3515,11 +3515,35 @@
  %7D);
-%0A%7D;
+//%3C/_ifThenFinally()%3E%0A%7D;%0A%0A%0A
 %0A%0A%0A%0A

Support 'sails console --dontLift' (uses .load() instead; useful for situations when you don't need an HTTP/WS server, when you can't bind to a port for whatever reason, or when you aren't even building a server and just want access to your models (e.g. migration scripts, scheduled jobs, etc.).