'use strict';

const path = require('path');
const Promise = require('bluebird');
const _ = require('lodash');
const Pebo = require('pebo');
Pebo.setPromise(Promise);

/**
 * Lager singleton definition
 *
 * The instance will register plugins and emit events
 * It is an Pebo event emitter
 */
class Lager extends Pebo {
  /**
   * Construct the lager instance
   *
   * The lager instance is a singleton that can explore the application configuration
   * give information about it, control it's validity and perform deployment
   *
   * It is possible to register plugins on the lager instance
   * A lager plugin can implements hooks to inject code and modify the behavior of
   * the lager instance
   * A lager plugin can create his own hooks for the lager instance, so it is possible
   * to create plugins for a lager plugin!
   * @constructor
   */
  constructor() {
    super();
    this.plugins = [];
    this.registerPlugin(require('./core-plugin'));
  }

  /**
   * Add a plugin to the lager instance
   * @param {Object} plugin
   * @returns {Lager}
   */
  registerPlugin(plugin) {
    if (plugin.setLagerInstance) {
      plugin.setLagerInstance(this);
    }
    this.plugins.push(plugin);

    // add hooks/event listeners
    plugin.hooks = plugin.hooks || [];
    _.map(plugin.hooks, (fn, event) => {
      this.when(event, fn);
    });
    return this;
  }

  /**
   * Retrieve a plugin by name
   * @param {string} name
   * @returns {Object}
   */
  getPlugin(name) {
    const plugin = _.find(this.plugins, plugin => {
      return plugin.name === name;
    });
    if (!plugin) {
      throw new Error('The plugin "' + name + '" is not registered in the Lager instance');
    }
    return plugin;
  }

  /**
   * Initialisation of the Lager instance
   * It looks for a configuration file and register plugins
   * @return {Promise} - a promise that resolves when the initialisation is finished
   */
  init(config) {
    config.plugins = config.plugins || [];

    try {
      _.forEach(config.plugins, pluginIdentifier => {
        let requireArg = pluginIdentifier;
        try {
          // Try to load plugins installed in node_modules
          require.resolve(requireArg);
        } catch (e) {
          try {
            // Try to load project specific plugins
            requireArg = path.join(process.cwd(), pluginIdentifier);
            require.resolve(requireArg);
          } catch (e) {
            requireArg = false;
            console.log('WARN: Lager could not find the plugin "' + pluginIdentifier + '"');
          }
        }
        if (requireArg) {
          lager.registerPlugin(require(requireArg), pluginIdentifier);
        }
      });
    } catch (e) {
      return Promise.reject(e);
    }

    return Promise.resolve();
  }
}

const lager = new Lager();

/**
 * This property allows the lager instance to share some key dependencies with plugins
 * @type {Object}
 */
lager.import = {
  Promise, _
};

module.exports = lager;

@@ -900,24 +900,50 @@
 ugins = %5B%5D;%0A
+    this.extensions = %5B%5D;%0A
     this.reg
@@ -981,16 +981,16 @@
 gin'));%0A
-
   %7D%0A%0A  /
@@ -1370,24 +1370,265 @@
 n);%0A    %7D);%0A
+%0A    // add extensions: functions that extends the Lager instance%0A    plugin.extensions = plugin.extensions %7C%7C %5B%5D;%0A    _.map(plugin.extensions, (fn, extensionName) =%3E %7B%0A      this.extensions%5Bplugin.name + ':' + extensionName%5D = fn;%0A    %7D);%0A%0A
     return t
@@ -1957,24 +1957,24 @@
 ce');%0A    %7D%0A
-
     return p
@@ -1981,24 +1981,495 @@
 lugin;%0A  %7D%0A%0A
+  /**%0A   * Call an extension%0A   * In case the extension has not been added to the Lager instance,%0A   * A Promise of the last argument will be returned%0A   * @return %7BPromise%7D%0A   */%0A  call() %7B%0A    // Extract arguments and extension name%0A    const args = Array.prototype.slice.call(arguments);%0A    const name = args.shift();%0A    if (this.extensions%5Bname%5D) %7B%0A      return this.extensions%5Bname%5D.apply(null, args);%0A    %7D%0A    return Promise.resolve(args%5Bargs.length - 1%5D);%0A  %7D%0A%0A
   /**%0A   * I

Add possibility for plugins to create "extensions"