'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _child_process = require('child_process');

var _bluebird = require('bluebird');

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _fsExtra = require('fs-extra');

var _fsExtra2 = _interopRequireDefault(_fsExtra);

var _cliColor = require('cli-color');

var _cliColor2 = _interopRequireDefault(_cliColor);

var _which = require('which');

var _which2 = _interopRequireDefault(_which);

var _ = require('../');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var npm = _which2.default.sync('npm');

var singleton = Symbol();
var singletonEnforcer = Symbol();

var Plugins = function () {
  function Plugins(enforcer) {
    var _this = this;

    _classCallCheck(this, Plugins);

    if (enforcer != singletonEnforcer) throw 'Cannot construct Plugins singleton';
    this.pluginsDir = _path2.default.join(_.config.root, 'node_modules') + _path2.default.sep;
    this.scriptsDir = _path2.default.join(_.config.root, 'scripts') + _path2.default.sep;
    this._plugins = [];
    this.fn = [];

    // Plugins
    if (_.config.plugins && Array.isArray(_.config.plugins)) {
      Array.prototype.forEach.call(_.config.plugins, function (pluginEntry) {
        var plugin = _this.getPluginConfig(_this.pluginsDir, pluginEntry);
        _this._plugins.push(plugin);
      });
    }

    // Scripts
    try {
      var directoryScripts = _fsExtra2.default.lstatSync(this.scriptsDir);
      if (directoryScripts.isDirectory()) {
        this._scripts = _.coreUtils.file.getFoldersSync(this.scriptsDir, false);
        Array.prototype.forEach.call(this._scripts, function (scriptEntry) {
          var name = scriptEntry.path.replace(_this.scriptsDir, '');
          var script = _this.getPluginConfig(_this.scriptsDir, name);
          _this._plugins.push(script);
        });
      }
    } catch (e) {}
  }

  _createClass(Plugins, [{
    key: 'getPluginConfig',
    value: function getPluginConfig(dir, entry) {
      // remove npm version if any
      var pluginId = entry.split('@')[0];

      // remove github version if any
      pluginId = pluginId.split('#')[0];

      // remove github path if any
      pluginId = _path2.default.basename(pluginId);

      var plugHook = _path2.default.join(dir, pluginId, _.config.hooks.url, 'hooks.js');
      var plugPartials = _path2.default.join(dir, pluginId, _.config.pluginsPartials);
      var plugTemplates = _path2.default.join(dir, pluginId, _.config.templates.url);
      var plugProcess = _path2.default.join(dir, pluginId, 'process');
      var plugRoutes = _path2.default.join(dir, pluginId, 'routes');
      var plugin = {
        hooks: null,
        partials: null,
        templates: null,
        process: null,
        routes: null
      };

      try {
        var fileHook = _fsExtra2.default.lstatSync(plugHook);
        if (fileHook.isFile()) {
          try {
            var h = require(plugHook);
          } catch (e) {
            console.log(e.stack);
            console.log(_cliColor2.default.green('[ Hint ]'), 'It seems that you don\'t have the npm module babel-preset-es2015 installed on your project');
          }
          plugin.hooks = h.default;
        }
      } catch (e) {
        plugin.hooks = null;
      }

      try {
        var directoryPartials = _fsExtra2.default.lstatSync(plugPartials);
        if (directoryPartials.isDirectory()) {
          plugin.partials = plugPartials;
        }
      } catch (e) {
        plugin.partials = null;
      }

      try {
        var directoryTemplates = _fsExtra2.default.lstatSync(plugTemplates);
        if (directoryTemplates.isDirectory()) {
          plugin.templates = plugTemplates;
        }
      } catch (e) {
        plugin.templates = null;
      }

      try {
        var directoryProcess = _fsExtra2.default.lstatSync(plugProcess);
        if (directoryProcess.isDirectory()) {
          plugin.process = {};
          var processFiles = _.coreUtils.file.getFilesSync(plugProcess, false);
          Array.prototype.forEach.call(processFiles, function (processFile) {
            plugin.process[_path2.default.basename(processFile, '.js')] = processFile;
          });
        }
      } catch (e) {
        plugin.process = null;
      }

      try {
        var directoryRoute = _fsExtra2.default.lstatSync(plugRoutes);
        if (directoryRoute.isDirectory()) {
          plugin.routes = {};

          var gets = _path2.default.join(plugRoutes, 'get');
          try {
            var directoryGets = _fsExtra2.default.lstatSync(gets);
            if (directoryGets.isDirectory()) {
              (function () {
                var routesGet = [];
                var routePaths = _.coreUtils.file.getFilesSync(gets, false);
                Array.prototype.forEach.call(routePaths, function (route) {
                  var pathUrl = '/abe/plugin/' + pluginId + '/' + _path2.default.basename(route, '.js') + '*';
                  var routeObject = { 'path': route, 'routePath': pathUrl };
                  routesGet.push(routeObject);
                });
                plugin.routes.get = routesGet;
              })();
            }
          } catch (e) {
            plugin.routes.get = null;
          }
          try {
            var posts = _path2.default.join(plugRoutes, 'post');
            var directoryPosts = _fsExtra2.default.lstatSync(gets);
            if (directoryPosts.isDirectory()) {
              (function () {
                var routesPost = [];
                var routePaths = _.coreUtils.file.getFilesSync(posts, false);
                Array.prototype.forEach.call(routePaths, function (route) {
                  var pathUrl = '/abe/plugin/' + pluginId + '/' + _path2.default.basename(route, '.js') + '*';
                  var routeObject = { 'path': route, 'routePath': pathUrl };
                  routesPost.push(routeObject);
                });
                plugin.routes.post = routesPost;
              })();
            }
          } catch (e) {
            plugin.routes.post = null;
          }
        }
      } catch (e) {
        plugin.routes = null;
      }

      return plugin;
    }
  }, {
    key: 'getProcess',
    value: function getProcess(fn) {
      var proc = null;
      if (typeof this._plugins !== 'undefined' && this._plugins !== null) {
        Array.prototype.forEach.call(this._plugins, function (plugin) {
          if (typeof plugin.process !== 'undefined' && plugin.process !== null && typeof plugin.process[fn] !== 'undefined' && plugin.process[fn] !== null) {
            proc = plugin.process[fn];
          }
        });
      }

      return proc;
    }
  }, {
    key: 'hooks',
    value: function hooks() {
      var _this2 = this;

      if (arguments.length > 0) {
        var args = [].slice.call(arguments);
        var fn = args.shift();

        if (this._plugins != null) {
          Array.prototype.forEach.call(this._plugins, function (plugin) {
            if (plugin.hooks != null && plugin.hooks[fn] != null) {
              args[0] = plugin.hooks[fn].apply(_this2, args);
            }
          });
        }
      } else {
        args = [''];
      }

      return args[0];
    }
  }, {
    key: 'getPartials',
    value: function getPartials() {
      var partials = [];
      Array.prototype.forEach.call(this._plugins, function (plugin) {
        if (typeof plugin.partials !== 'undefined' && plugin.partials !== null) {
          partials.push(plugin.partials);
        }
      });

      return partials;
    }
  }, {
    key: 'getRoutes',
    value: function getRoutes() {
      var routes = [];
      Array.prototype.forEach.call(this._plugins, function (plugin) {
        if (typeof plugin.routes !== 'undefined' && plugin.routes !== null) {
          routes = routes.concat(plugin.routes);
        }
      });

      return routes;
    }
  }, {
    key: 'removePlugin',
    value: function removePlugin(plugin) {
      var pluginName = plugin.split('@')[0];
      pluginName = pluginName.split('#')[0];
      if (_.config.localConfigExist()) {
        (function () {
          var json = _.config.getLocalConfig();
          if (typeof json.plugins !== 'undefined' && json.plugins !== null) {
            Array.prototype.forEach.call(json.plugins, function (plugged, index) {
              if (pluginName === _path2.default.basename(plugged.split('@')[0].split('#')[0])) {
                json.plugins.splice(index, 1);
                _.config.save(json);
              }
            });
          }
        })();
      }
    }
  }, {
    key: 'updatePlugin',
    value: function updatePlugin(plugin) {
      var json = {};
      var createLocalConfig = true;
      var pluginName = plugin.split('@')[0];
      pluginName = pluginName.split('#')[0];

      if (_.config.localConfigExist()) {
        json = _.config.getLocalConfig();
        createLocalConfig = false;
      }

      if (typeof json.plugins === 'undefined' || json.plugins === null) {
        json.plugins = [plugin];
      } else {
        var found = false;
        Array.prototype.forEach.call(json.plugins, function (plugged, index) {
          if (pluginName === plugged.split('@')[0].split('#')[0]) {
            json.plugins[index] = plugin;
            found = true;
          }
        });
        if (!found) {
          json.plugins.push(plugin);
        }
      }

      if (createLocalConfig) {
        console.log(_cliColor2.default.green('[ Hint ]'), 'creating a local config abe.json with your plugin definition', _cliColor2.default.cyan.underline('https://github.com/AdFabConnect/abejs/blob/master/docs/abe-config.md'));
      }

      _.config.save(json);
    }
  }, {
    key: 'uninstall',
    value: function uninstall(dir, plugin) {
      if (plugin !== null) {
        this.remove(dir, plugin).then(function () {

          return 0;
        });
      } else {
        console.log(_cliColor2.default.cyan('no plugin with this name found'));

        return 0;
      }
    }
  }, {
    key: 'install',
    value: function install(dir) {
      var _this3 = this;

      var plugin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

      if (plugin !== null) {
        this.add(dir, plugin).then(function () {

          return 0;
        });
      } else {
        if (_.config.plugins && Array.isArray(_.config.plugins)) {
          var ps = [];
          Array.prototype.forEach.call(_.config.plugins, function (plugin) {
            ps.push(_this3.add(dir, plugin));
          });

          _bluebird.Promise.all(ps).then(function () {

            return 0;
          });
        } else {
          console.log(_cliColor2.default.cyan('no plugin found'));

          return 0;
        }
      }
    }
  }, {
    key: 'remove',
    value: function remove(dir, plugin) {
      var _this4 = this;

      var p = new _bluebird.Promise(function (resolve) {
        try {
          console.log(_cliColor2.default.green('spawn'), _cliColor2.default.cyan('npm uninstall ' + plugin));
          // const npmUninstall = spawn('npm', ['uninstall', pluginDir]);
          var npmUninstall = (0, _child_process.spawn)(npm, ['uninstall', '--save', plugin], { cwd: dir });

          npmUninstall.stdout.on('data', function (data) {
            console.log('' + data);
          });

          npmUninstall.stderr.on('data', function (data) {
            console.log('' + data);
          });

          npmUninstall.on('close', function (code) {
            console.log(_cliColor2.default.cyan('child process exited with code'), code);

            if (code == 0) {
              _this4.removePlugin(plugin);
            }

            resolve();
          });

          npmUninstall.on('error', function (err) {
            console.log(_cliColor2.default.red('cannot uninstall npm dependencies for'), dir);
            console.log(err);
            resolve(err);
          });
        } catch (err) {
          console.log(_cliColor2.default.cyan('uninstall'), err);
          resolve(err);
        }
      });

      return p;
    }
  }, {
    key: 'add',
    value: function add(dir, plugin) {
      var _this5 = this;

      var p = new _bluebird.Promise(function (resolve) {
        try {
          console.log(_cliColor2.default.green('spawn'), _cliColor2.default.cyan('npm install ' + plugin));
          // const npmInstall = spawn('npm', ['install', pluginDir]);
          var npmInstall = (0, _child_process.spawn)(npm, ['install', '--save', plugin], { cwd: dir });

          npmInstall.stdout.on('data', function (data) {
            console.log('' + data);
          });

          npmInstall.stderr.on('data', function (data) {
            console.log('' + data);
          });

          npmInstall.on('close', function (code) {
            console.log(_cliColor2.default.cyan('child process exited with code'), code);

            if (code == 0) {
              _this5.updatePlugin(plugin);
            }

            resolve();
          });

          npmInstall.on('error', function (err) {
            console.log(_cliColor2.default.red('cannot install npm dependencies for'), dir);
            console.log(err);
            resolve(err);
          });
        } catch (err) {
          console.log(_cliColor2.default.cyan('install'), err);
          resolve(err);
        }
      });

      return p;
    }
  }], [{
    key: 'instance',
    get: function get() {
      if (!this[singleton]) {
        this[singleton] = new Plugins(singletonEnforcer);
      }
      return this[singleton];
    }
  }]);

  return Plugins;
}();

exports.default = Plugins;