'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 _handlebars = require('handlebars');

var _handlebars2 = _interopRequireDefault(_handlebars);

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

var _fsExtra2 = _interopRequireDefault(_fsExtra);

var _mkdirp = require('mkdirp');

var _mkdirp2 = _interopRequireDefault(_mkdirp);

var _events = require('events');

var _events2 = _interopRequireDefault(_events);

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _watch = require('watch');

var _watch2 = _interopRequireDefault(_watch);

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 singleton = Symbol();
var singletonEnforcer = Symbol();

var Manager = function () {
  function Manager(enforcer) {
    _classCallCheck(this, Manager);

    if (enforcer != singletonEnforcer) throw 'Cannot construct Json singleton';

    _handlebars2.default.templates = _handlebars2.default.templates || {};
    this.loadHbsTemplates();
  }

  _createClass(Manager, [{
    key: 'init',
    value: function init() {
      var _this = this;

      this._pathPartials = _path2.default.join(_.config.root, _.config.partials);
      this._pathTemplate = _path2.default.join(_.config.root, _.config.templates.url);
      this._pathStructure = _path2.default.join(_.config.root, _.config.structure.url);
      this._pathReference = _path2.default.join(_.config.root, _.config.reference.url);
      this._pathData = _path2.default.join(_.config.root, _.config.data.url);
      this._watchersStart();

      this.updateStructureAndTemplates();
      var p = new Promise(function (resolve) {
        _this.getKeysFromSelect().then(function () {
          resolve();
        }, function (e) {
          console.log('Manager.init', e);
          resolve();
        }).catch(function (e) {
          console.log('Manager.init', e);
        });
      });

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

      this.events = {
        template: new _events2.default.EventEmitter(0),
        structure: new _events2.default.EventEmitter(0),
        reference: new _events2.default.EventEmitter(0)
      };

      // watch template folder
      try {
        _fsExtra2.default.accessSync(this._pathTemplate, _fsExtra2.default.F_OK);
        this._watchTemplateFolder = _watch2.default.createMonitor(this._pathTemplate, function (monitor) {
          monitor.on('created', function () {
            _this2.getKeysFromSelect();
            _this2.updateStructureAndTemplates();
            _this2.events.template.emit('update');
          });
          monitor.on('changed', function () {
            _this2.getKeysFromSelect();
            _this2.updateStructureAndTemplates();
            _this2.events.template.emit('update');
          });
          monitor.on('removed', function () {
            _this2.getKeysFromSelect();
            _this2.updateStructureAndTemplates();
            _this2.events.template.emit('update');
          });
        });
      } catch (e) {
        console.log('the directory ' + this._pathTemplate + ' does not exist');
      }

      // watch partial folder
      try {
        _fsExtra2.default.accessSync(this._pathPartials, _fsExtra2.default.F_OK);
        this._watchPartialsFolder = _watch2.default.createMonitor(this._pathPartials, function (monitor) {
          monitor.on('created', function () {
            _this2.getKeysFromSelect();
            _this2.updateStructureAndTemplates();
            _this2.events.template.emit('update');
          });
          monitor.on('changed', function () {
            _this2.getKeysFromSelect();
            _this2.updateStructureAndTemplates();
            _this2.events.template.emit('update');
          });
          monitor.on('removed', function () {
            _this2.getKeysFromSelect();
            _this2.updateStructureAndTemplates();
            _this2.events.template.emit('update');
          });
        });
      } catch (e) {
        console.log('the directory ' + this._pathPartials + ' does not exist');
      }

      try {
        _fsExtra2.default.accessSync(this._pathStructure, _fsExtra2.default.F_OK);
        this._watchStructure = _watch2.default.createMonitor(this._pathStructure, function (monitor) {
          monitor.on('created', function () {
            _this2.updateStructureAndTemplates();
            _this2.events.structure.emit('update');
          });
          monitor.on('changed', function () {
            _this2.updateStructureAndTemplates();
            _this2.events.structure.emit('update');
          });
          monitor.on('removed', function () {
            _this2.updateStructureAndTemplates();
            _this2.events.structure.emit('update');
          });
        });
      } catch (e) {
        console.log('the directory ' + this._pathStructure + ' does not exist');
      }

      try {
        _fsExtra2.default.accessSync(this._pathReference, _fsExtra2.default.F_OK);
        this._watchReferenceFolder = _watch2.default.createMonitor(this._pathReference, function (monitor) {
          monitor.on('created', function (f) {
            _this2.updateReferences(f);
            _this2.events.reference.emit('update');
          });
          monitor.on('changed', function (f) {
            _this2.updateReferences(f);
            _this2.events.reference.emit('update');
          });
          monitor.on('removed', function () {
            _this2.updateReferences();
            _this2.events.reference.emit('update');
          });
        });
      } catch (e) {
        console.log('the directory ' + this._pathReference + ' does not exist');
      }
    }
  }, {
    key: 'getKeysFromSelect',
    value: function getKeysFromSelect() {
      var _this3 = this;

      this._whereKeys = [];
      var p = new Promise(function (resolve) {

        _.cmsTemplates.template.getTemplatesAndPartials(_this3._pathTemplate).then(function (templatesList) {

          return _.cmsTemplates.template.getTemplatesTexts(templatesList).then(function (templatesText) {

            return _.cmsTemplates.template.getAbeRequestWhereKeysFromTemplates(templatesText).then(function (whereKeys) {
              _this3._whereKeys = whereKeys;
              _this3._slugs = _.cmsTemplates.template.getAbeSlugFromTemplates(templatesText);
              _this3._precontribution = _.cmsTemplates.template.getAbePrecontribFromTemplates(templatesText);
              _this3.updateList();
              resolve();
            }, function (e) {
              console.log('Reject: Manager.findRequestColumns', e);
            }).catch(function (e) {
              console.log('Error: Manager.findRequestColumns', e);
            });
          }, function (e) {
            console.log('Reject: Manager.getTemplatesTexts', e);
          }).catch(function (e) {
            console.log('Error: Manager.getTemplatesTexts', e);
          });
        }, function (e) {
          console.log('Manager.getKeysFromSelect', e);
        }).catch(function (e) {
          console.log('Manager.getKeysFromSelect', e);
        });
      });

      return p;
    }
  }, {
    key: 'getStructureAndTemplates',
    value: function getStructureAndTemplates() {

      return this._structureAndTemplates;
    }
  }, {
    key: 'updateStructureAndTemplates',
    value: function updateStructureAndTemplates() {
      this._structureAndTemplates = _.cmsTemplates.template.getStructureAndTemplates();
    }
  }, {
    key: 'getThumbsList',
    value: function getThumbsList() {
      if (typeof this._thumbs === 'undefined' || this._thumbs === null) this._thumbs = _.cmsMedia.image.getThumbsList();
      return this._thumbs;
    }
  }, {
    key: 'addThumbsToList',
    value: function addThumbsToList(thumb) {
      if (this._thumbs) this._thumbs.push(thumb);
    }
  }, {
    key: 'getReferences',
    value: function getReferences() {
      if (typeof this._references === 'undefined' || this._references === null) this.updateReferences();
      return this._references;
    }
  }, {
    key: 'getPrecontribution',
    value: function getPrecontribution() {
      return this._precontribution;
    }
  }, {
    key: 'getSlugs',
    value: function getSlugs() {
      return this._slugs;
    }
  }, {
    key: 'updateReferences',
    value: function updateReferences(referenceName) {
      var references = _.cmsReference.reference.getFiles();
      if (referenceName && references[referenceName]) this._references[referenceName] = references[referenceName];else this._references = references;

      return this;
    }
  }, {
    key: 'getList',
    value: function getList() {

      return this._list;
    }
  }, {
    key: 'getListWithStatusOnFolder',
    value: function getListWithStatusOnFolder(status) {
      var folder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';

      var list = [];
      folder = _path2.default.join(_.config.root, _.config.data.url, folder);
      Array.prototype.forEach.call(this._list, function (file) {
        if (typeof file[status] !== 'undefined' && file[status] !== null && file.path.indexOf(folder) > -1) {
          list.push(file);
        }
      });

      return list;
    }
  }, {
    key: 'setList',
    value: function setList(list) {
      this._list = list;

      return this;
    }

    /**
     * return true if postUrl is found in the Manager list
     * @param {String} postUrl The url path of the file
     */

  }, {
    key: 'postExist',
    value: function postExist(postUrl) {
      var parentRelativePath = _.cmsData.fileAttr.delete(postUrl.split('/').join(_path2.default.sep).replace('.' + _.config.files.templates.extension, '.json')).replace(/^\//, '');
      var found = _.coreUtils.array.find(this._list, 'parentRelativePath', parentRelativePath);

      if (found.length > 0) {
        return true;
      }
      return false;
    }

    /**
     * When a post is modified or created, this method is called so that the manager updates the list with the updated/new item
     * @param {String} pathFile The full path to the post
     */

  }, {
    key: 'updatePostInList',
    value: function updatePostInList(pathFile) {
      var parentRelativePath = _.cmsData.fileAttr.delete(pathFile).replace(this._pathData + _path2.default.sep, '');
      var found = _.coreUtils.array.find(this._list, 'parentRelativePath', parentRelativePath);
      var json = _.cmsData.file.get(pathFile);
      var merged = {};
      var revision = _.cmsData.file.getFileObject(pathFile);
      revision = _.cmsData.file.getAbeMeta(revision, json);
      Array.prototype.forEach.call(this._whereKeys, function (key) {
        var keyFirst = key.split('.')[0];
        revision[keyFirst] = json[keyFirst];
      });

      if (found.length > 0) {
        var index = found[0];
        merged[parentRelativePath] = this._list[index];
        merged[parentRelativePath].revisions.push(JSON.parse(JSON.stringify(revision)));
        var sortedResult = _.cmsData.revision.sortRevisions(merged);
        // Does the publish version has been removed (in the case of unpublish) ? 
        if (sortedResult[0]['publish'] && !_.coreUtils.file.exist(sortedResult[0]['publish']['path'])) {
          delete sortedResult[0]['publish'];
        }
        this._list[index] = sortedResult[0];
      } else {
        var rev = [];
        rev.push(revision);
        merged = _.cmsData.revision.mergeRevisions(rev);
        var _sortedResult = _.cmsData.revision.sortRevisions(merged);
        this._list.push(_sortedResult[0]);
      }

      this._list.sort(_.coreUtils.sort.predicatBy('date', -1));
    }

    /**
     * When a post is deleted, this method is called so that the manager updates the list with the removed item
     * @param {String} pathFile The full path to the post
     */

  }, {
    key: 'removePostFromList',
    value: function removePostFromList(pathFile) {
      var parentRelativePath = _.cmsData.fileAttr.delete(pathFile);
      parentRelativePath = pathFile.indexOf(_path2.default.sep) === 0 ? parentRelativePath.substring(1) : parentRelativePath;
      parentRelativePath = parentRelativePath.replace('.' + _.config.files.templates.extension, '.json');
      this._list = _.coreUtils.array.removeByAttr(this._list, 'parentRelativePath', parentRelativePath);
    }

    /**
     * This method loads all posts into an array with values used in "select" statements from templates
     * + abe_meta data
     * @return {Array} Array of objects representing the posts including their revisions
     */

  }, {
    key: 'updateList',
    value: function updateList() {
      this._list = _.cmsData.file.getAllWithKeys(this._whereKeys);
      this._list.sort(_.coreUtils.sort.predicatBy('date', -1));
      console.log('Manager updated');
    }
  }, {
    key: 'getPage',
    value: function getPage() {
      var start = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
      var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
      var sortField = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'date';
      var sortDir = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : -1;
      var search = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : '';
      var searchFields = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : ['abe_meta.link', 'abe_meta.template'];

      var total = this._list.length;
      var totalFiltered = total;
      var list = this._list.slice();

      if (search !== '') {
        var searches = search.split(' ');
        for (var i = 0; i < searches.length; i++) {
          list = _.coreUtils.array.facet(list, searchFields, searches[i]);
        }

        totalFiltered = list.length;
      }

      if (sortField != 'date' || sortDir != -1) {
        list.sort(_.coreUtils.sort.predicatBy(sortField, sortDir));
      }

      list = list.slice(start, start + length);

      return {
        'recordsTotal': total,
        'recordsFiltered': totalFiltered,
        'data': list
      };
    }
  }, {
    key: 'addHbsTemplate',
    value: function addHbsTemplate(templateId) {
      var pathTemplate = _path2.default.join(_.config.root, _.config.templates.url, 'hbs', templateId) + '.hbs';
      var tmpl = eval('(function(){return ' + _fsExtra2.default.readFileSync(pathTemplate) + '}());');
      _handlebars2.default.templates[templateId] = _handlebars2.default.template(tmpl);
    }
  }, {
    key: 'loadHbsTemplates',
    value: function loadHbsTemplates() {
      var pathTemplate = _path2.default.join(_.config.root, _.config.templates.url, 'hbs');

      try {
        var directory = _fsExtra2.default.lstatSync(pathTemplate);
        if (!directory.isDirectory()) {
          _mkdirp2.default.sync(pathTemplate);
        }
      } catch (e) {
        _mkdirp2.default.sync(pathTemplate);
      }

      _fsExtra2.default.readdirSync(pathTemplate).forEach(function (file) {
        if (file.indexOf('.hbs') > -1) {
          var originalTemplatePath = _path2.default.join(_.config.root, _.config.templates.url) + '/' + file.replace('.hbs', '.' + _.config.files.templates.extension);

          try {
            var originalTemplateStat = _fsExtra2.default.statSync(originalTemplatePath);
            var originalTemplateMdate = originalTemplateStat.mtime;
            var stat = _fsExtra2.default.statSync(_path2.default.join(pathTemplate, file));
            var mdate = stat.mtime;

            // if the original template has been updated after precompilation, I delete the precompiled file
            // else I add it to the hbs template array
            if (originalTemplateMdate > mdate) {
              _fsExtra2.default.unlinkSync(_path2.default.join(pathTemplate, file));
            } else {
              var tmpl = eval('(function(){return ' + _fsExtra2.default.readFileSync(_path2.default.join(pathTemplate, file)) + '}());');
              _handlebars2.default.templates[file.replace('.hbs', '')] = _handlebars2.default.template(tmpl);
            }
          } catch (err) {
            console.log('The original template has not been found or the hbs template is corrupted');
            console.log(originalTemplatePath);
            console.log(err);
          }
        }
      });
    }
  }], [{
    key: 'instance',
    get: function get() {
      if (!this[singleton]) {
        this[singleton] = new Manager(singletonEnforcer);
      }
      return this[singleton];
    }
  }]);

  return Manager;
}();

exports.default = Manager;