var utile = require('utile'),
async = utile.async,
events = require('eventemitter2'),
bootstrapper = require('./bootstrapper'),
common = require('./common'),
features = require('./features');
var App = exports.App = function (options) {
var self = this;
options = options || {};
this.root = options.root;
this.delimiter = options.delimiter || '::';
events.EventEmitter2.call(this, {
delimiter: this.delimiter,
wildcard: true
});
this.options = options;
this.env = options.env || process.env['NODE_ENV'] || 'development'
this.plugins = options.plugins || {};
this.initialized = false;
this.bootstrapper = options.bootstrapper || bootstrapper;
this.initializers = {};
this.initlist = [];
this.bootstrapper.bootstrap(this);
};
utile.inherits(App, events.EventEmitter2);
App.prototype.init = function (options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
if (this.initialized) {
return callback();
}
var self = this;
options = options || {};
callback = callback || function () {};
this.env = options.env || this.env;
this.options = common.mixin({}, this.options, options);
function onComplete() {
self.initialized = true;
self.emit('init');
callback();
}
function ensureFeatures (err) {
return err
? onError(err)
: features.ensure(this, onComplete);
}
function initPlugin(plugin, next) {
if (typeof self.initializers[plugin] === 'function') {
return self.initializers[plugin].call(self, function (err) {
if (err) {
return next(err);
}
self.emit(['plugin', plugin, 'init']);
self.initializers[plugin] = true;
next();
});
}
next();
}
function initPlugins() {
async.forEach(self.initlist, initPlugin, ensureFeatures);
}
function onError(err) {
self.emit(['error', 'init'], err);
callback(err);
}
this.bootstrapper.init(this, initPlugins);
};
App.prototype.use = function (plugin, options, callback) {
options = options || {};
if (typeof plugin === 'undefined') {
console.log('Cannot load invalid plugin!');
if (callback) {
callback(new Error('Invalid plugin'));
}
return;
}
var name = plugin.name,
self = this;
if (!name) {
name = common.uuid();
}
if (this.plugins[name]) {
return callback && callback();
}
this.plugins[name] = plugin;
this.options[name] = common.mixin({}, options, this.options[name] || {});
if (this.plugins[name].attach && options.attach !== false) {
this.plugins[name].attach.call(this, options);
}
if (options.init === false) {
return;
}
if (!this.initialized) {
this.initializers[name] = plugin.init || true;
this.initlist.push(name);
}
else if (plugin.init) {
plugin.init.call(this, function (err) {
var args = err
? [['plugin', name, 'error'], err]
: [['plugin', name, 'init']];
self.emit.apply(self, args);
if (callback) {
return err ? callback(err) : callback();
}
});
}
};
App.prototype.remove = function (name) {
if (name.name) {
name = name.name;
}
if (this.plugins[name] && this.plugins[name].detach) {
this.plugins[name].detach.call(this);
}
delete this.plugins[name];
delete this.options[name];
delete this.initializers[name];
var init = this.initlist.indexOf(name);
if (init !== -1) {
this.initlist.splice(1, init);
}
}
App.prototype.inspect = function () {
};