'use strict';

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

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _eventemitter = require('eventemitter2');

var _eventemitter2 = _interopRequireDefault(_eventemitter);

var _mkdirp = require('mkdirp');

var _mkdirp2 = _interopRequireDefault(_mkdirp);

var _validator = require('./validator');

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

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new _bluebird2.default(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return _bluebird2.default.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

const PLACING_STEP = 250;

class FlowProvider extends _eventemitter2.default {
  constructor({ logger, botfile, projectLocation, ghostManager }) {
    super({
      wildcard: true,
      maxListeners: 100
    });

    this.logger = logger;
    this.botfile = botfile;
    this.projectLocation = projectLocation;
    this.ghostManager = ghostManager;
    this.flowsDir = this.botfile.flowsDir || './flows';

    _mkdirp2.default.sync(_path2.default.dirname(this.flowsDir));
    this.ghostManager.addRootFolder(this.flowsDir, { filesGlob: '**/*.json' });
  }

  loadAll() {
    var _this = this;

    return _asyncToGenerator(function* () {
      const flows = yield _this.ghostManager.directoryListing(_this.flowsDir, '.flow.json').map((() => {
        var _ref = _asyncToGenerator(function* (flowPath) {
          const [flow, uiEq] = (yield _bluebird2.default.map([flowPath, _this._uiPath(flowPath)], function (filePath) {
            return _this.ghostManager.readFile(_this.flowsDir, filePath);
          })).map(JSON.parse);

          if (!flow) {
            return null;
          }

          const schemaError = (0, _validator.validateFlowSchema)(flow);
          if (schemaError) {
            _this.logger.warn(schemaError);
            return null;
          }

          flow.links = uiEq.links;

          // Take position from UI files or create default position
          let unplacedIndex = -1;
          flow.nodes = flow.nodes.map(function (node) {
            const position = _lodash2.default.get(_lodash2.default.find(uiEq.nodes, { id: node.id }), 'position');
            unplacedIndex = position ? unplacedIndex : unplacedIndex + 1;

            return _extends({}, node, {
              x: position ? position.x : 50 + unplacedIndex * PLACING_STEP,
              y: position ? position.y : (_lodash2.default.maxBy(flow.nodes, 'y') || { y: 0 }).y + PLACING_STEP
            });
          });

          return _extends({
            name: flowPath,
            location: flowPath,
            nodes: flow.nodes.filter(Boolean)
          }, _lodash2.default.pick(flow, 'version', 'catchAll', 'startNode', 'links', 'skillData'));
        });

        return function (_x) {
          return _ref.apply(this, arguments);
        };
      })());

      return flows.filter(Boolean);
    })();
  }

  saveFlows(flows) {
    var _this2 = this;

    return _asyncToGenerator(function* () {
      if (!flows.find(function ({ flow }) {
        return flow === 'main.flow.json';
      })) {
        throw new Error(`[Flow] Expected flows list to contain 'main.flow.json'`);
      }
      const flowsToSave = yield _bluebird2.default.mapSeries(flows, function (flow) {
        return _this2._prepareSaveFlow(flow);
      });
      const flowsSavePromises = _lodash2.default.flatten(flowsToSave.map(function ({ flowPath, uiPath, flowContent, uiContent }) {
        return [_this2.ghostManager.upsertFile(_this2.flowsDir, flowPath, JSON.stringify(flowContent, null, 2)), _this2.ghostManager.upsertFile(_this2.flowsDir, uiPath, JSON.stringify(uiContent, null, 2))];
      }));

      const pathsToOmit = _lodash2.default.flatten(flowsToSave.map(function (flow) {
        return [flow.flowPath, flow.uiPath];
      }));

      const flowFiles = yield _this2.ghostManager.directoryListing(_this2.flowsDir, '.json', pathsToOmit);
      const flowsDeletePromises = flowFiles.map(function (filePath) {
        return _this2.ghostManager.deleteFile(_this2.flowsDir, filePath);
      });

      yield _bluebird2.default.all(flowsSavePromises.concat(flowsDeletePromises));

      _this2.emit('flowsChanged');
    })();
  }

  _prepareSaveFlow(flow) {
    var _this3 = this;

    return _asyncToGenerator(function* () {
      flow = _extends({}, flow, { version: '0.1' });

      const schemaError = (0, _validator.validateFlowSchema)(flow);
      if (schemaError) {
        throw new Error(schemaError);
      }

      // What goes in the ui.json file
      const uiContent = {
        nodes: flow.nodes.map(function (node) {
          return { id: node.id, position: _lodash2.default.pick(node, 'x', 'y') };
        }),
        links: flow.links

        // What goes in the .flow.json file
      };const flowContent = _extends({}, _lodash2.default.pick(flow, 'version', 'catchAll', 'startNode', 'skillData'), {
        nodes: flow.nodes.map(function (node) {
          return _lodash2.default.omit(node, 'x', 'y', 'lastModified');
        })
      });

      const flowPath = flow.location;
      return { flowPath, uiPath: _this3._uiPath(flowPath), flowContent, uiContent };
    })();
  }

  _uiPath(flowPath) {
    return flowPath.replace(/\.flow\.json/i, '.ui.json');
  }
}
exports.default = FlowProvider;
//# sourceMappingURL=provider.js.map