/**
 * @author Dmitriy Yurchenko <evildev@evildev.ru>
 * @link http://nyama.evildev.ru/
 * @copyright Copyright (c) Dmitriy Yurchenko <evildev@evildev.ru>, 2014
 * @license http://nyama.evildev.ru/license/
 */

'use strict';

/**
 * Nyama application class.
 * @private {object} _params
 * @class Application
 */
Nyama.defineClass('Nyama.base.Application', {
	/**
	 * @var {object} utils container.
	 */
	utils: {},

	/**
	 * @constructor
	 */
	constructor: function(params) {
		Nyama.app = this;
		this.config = params;
	},

	/**
	 * @returns {string} base path's application.
	 */
	getBasePath: function() {
		return this.config.basePath || (__dirname + '/../../application');
	},

	/**
	 * Init application.
	 * @param {Function} initCallback
	 */
	init: function(initCallback) {
		//	Load utils.
		var utils = _.map(_.fs.readdirSync(__dirname + '/../utils'), function(file) {
			return __dirname + '/../utils/' + file;
		});

		_.each(utils, function(file) {
			var name = _.fs.baseName(file, '.js'),
				className = _.str.ucFirst(name),
				params = _.isObject(this.config.utils) ? this.config.utils[name] : {};

			if (_.fs.isFile(file)) {
				require(file);
				this.utils[name] = new Nyama.utils[className](params);
			}
		}, this);

		//	Init components.
		var tasks = [],
			userComponentsPath = Nyama.app.getBasePath() + '/components',
			files = _.extend(
				//	Core components.
				_.map(_.fs.readdirSync(__dirname + '/../components'), function(file) {
					return __dirname + '/../components/' + file;
				}),
				//	User's components.
				_.fs.isDir(userComponentsPath) ? _.map(_.fs.readdirSync(userComponentsPath), function(file) {
					return Nyama.app.getBasePath() + '/components/' + file;
				}) : []
			);

		//	Load components.
		_.each(files, function(file) {
			tasks.push(function(callback) {
				var name = _.fs.baseName(file, '.js'),
					className = _.str.ucFirst(name);

				require(file);

				this[name] = new Nyama.components[className]();
				if (_.isFunction(this[name].init)) {
					this[name].init(_.isObject(this.config.components) ? this.config.components[name] : {}, callback);
				}
				else {
					callback();
				}
			}.bind(this));
		}, this);

		_.async.parallel(tasks, initCallback);
	},

	/**
	 * Run application.
	 */
	run: function() {
		this.init(function(error) {
			if (error) {
				this.end(1, error);
			}

			var commandName = _.str.ucFirst(_.first(process.argv.slice(2)) || 'index'),
				command,
				parsedArgs,
				_params = {},
				params = [];

			require(this.getBasePath() + '/commands/' + commandName.toLowerCase() + '.js');

			command = new Nyama.commands[commandName]();
			parsedArgs = command.run.toString().match(/^function\s.*\((.*)\)/)[1].split(',');

			_.each(process.argv.slice(3), function(arg) {
				if (arg.substr(0, 2) === '--') {
					var _data = arg.split('=');
					_params[_data[0].substr(2)] = _data[1];
				}
			});

			_.each(parsedArgs, function(argument) {
				argument = (argument || '').trim();
				if (_params[argument]) {
					params.push(_params[argument]);
				}
			});

			//	Add app to params
			params.unshift(this);

			//	Execute!
			command.run.apply(command, params);
		}.bind(this));
	},

	/**
	 * Terminates the application.
	 * @param {number} code
	 * @param {string} message
	 */
	end: function(code, message) {
		if (message) {
			_.intel.error(message);
		}
		process.exit(code || 1);
	},

	/**
	 * Returns param value from config file.
	 * @param {string} key
	 * @param {mixin} defValue
	 */
	getParam: function(key, defValue) {
		return _.isUndefined(this.config.params[key]) ? defValue : this.config.params[key];
	}
});
@@ -2890,24 +2890,53 @@
 %09%09%7D%0A%09%09%09%7D);%0A%0A
+%09%09%09//%09Ignore first variable.%0A
 %09%09%09_.each(pa
@@ -2943,16 +2943,25 @@
 rsedArgs
+.slice(1)
 , functi
@@ -3019,19 +3019,41 @@
 ();%0A%09%09%09%09
-if 
+params.push(_.isUndefined
 (_params
@@ -3068,27 +3068,22 @@
 t%5D) 
-%7B%0A%09%09%09%09%09params.push(
+? undefined : 
 _par
@@ -3098,22 +3098,16 @@
 ment%5D);%0A
-%09%09%09%09%7D%0A
 %09%09%09%7D);%0A%0A

Fix command function params order