Source: lib/tcl.js


'use strict';

var binding = require( 'bindings' )( 'tcl' );
var Result  = require( './result' );

/**
*   Tcl Interpreter bridge
*
*   @constructor
*/
var Tcl = function () {

	// tcl interpreter binding
	this._binding = new binding.TclBinding();

	// intialise internals
	this._version = null;
	this.$inject();

};


/**
*   Execute a Tcl command using the Tcl Interpreter binding. This is an
*   asynchronous call and a new Tcl Interpreter instance is used for
*   each execution.
*
*   @param {string} cmd - command to execute
*   @param {Tcl~cmdCallback} callback - callback method to handle
*          the response
*/
Tcl.prototype.cmd = function ( cmd, callback ) {

	var self = this;

	this._binding.cmd( cmd, function ( err, data ) {

		var result = null;
		if (! err ) {
			result = new Result( data, self._binding );
		}

		if ( callback ) {
			callback( err, result );
		}

	} );

};


/**
*   Alias for {@link Tcl#cmd}
*
*   @method
*   @see Tcl#cmd
*/
Tcl.prototype.eval = Tcl.prototype.cmd;


/**
*   Execute a Tcl command synchronously using the Tcl Interpreter binding.
*   This will use a shared Tcl Interpreter and can share data between two
*   executions (e.g. global variable, loaded libraries etc.)
*
*   @param {string} cmd - Command to execute
*   @return {Result} Result object containing response data
*   @throws {Error} Error object containing error data
*/
Tcl.prototype.cmdSync = function ( cmd ) {

	try {
		return new Result( this._binding.cmdSync( cmd ), this._binding );
	} catch ( e ) {
		throw e;
	}

};


/**
*   Alias for {@link Tcl#cmdSync}
*
*   @method
*   @see Tcl#cmdSync
*/
Tcl.prototype.evalSync = Tcl.prototype.cmdSync;


/**
*   Alias for {@link Tcl#cmdSync}
*
*   @method
*   @see Tcl#cmdSync
*/
Tcl.prototype.$ = Tcl.prototype.cmdSync;


/**
*   Inject Tcl commands (returned by `info commands`) as javascript functions
*   into the object.
*/
Tcl.prototype.$inject = function () {

	var self = this;
	var cmds = self.$( 'info commands' ).toArray();

	var inject = function ( cmd ) {
		return function () {
			var args = '';
			for ( var i = 0; i < arguments.length; i++ ) {
				args += ' ' + arguments[i];
			}

			return self.$( cmd + args );
		};
	};

	cmds.forEach( function ( cmd ) {
		self.$[ cmd ] = inject( cmd );
	} );

};


/**
*   load a Tcl module and refresh internal Tcl command references
*/
Tcl.prototype.load = function ( module ) {
	var result = this.$( 'load {' + module + '}' );
	this.$inject();
	return result;
};


/**
*   Add a Tcl command to the asynchronous processing queue. Each command
*   added will be executed using a single worker thread outside of the
*   main event loop. Each command shares the same worker thread and the
*   Tcl interpreter instance and will share states.
*
*   @param {string} cmd - command to execute
*   @param {Tcl~cmdCallback} callback - callback method to handle
*          the response
*/
Tcl.prototype.queue = function ( cmd, callback ) {

	this._binding.queue( cmd, function ( err, data ) {

		var result = null;
		if (! err ) {
			result = new Result( data, this._binding );
		}

		if ( callback ) {
			callback( err, result );
		}

	} );

};


/**
*   Source a Tcl script and refresh internal Tcl command references
*/
Tcl.prototype.source = function ( file ) {
	var result = this.$( 'source {' + file + '}' );
	this.$inject();
	return result;
};


/**
*   Returns the Tcl Interpreter version
*
*   @return {string} Tcl version
*/
Tcl.prototype.version = function () {

	if (! this._version ) {
		this._version = this._binding.cmdSync( 'info patchlevel' );
	}

	return this._version;

};



// jsdoc definitions
/**
*   Error first callback method to return error and response data after executing
*   a Tcl command asynchronously
*
*   @callback Tcl~cmdCallback
*   @param {(Error|null)} err - JavaScript Error object with error details upon error or null
*   @param {Result} result - object containing response data from the executed Tcl command
*/


module.exports = Tcl;