text: 'use strict';
  
  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; }; }();
  
  function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  /**
   * Copyright (c) 2017 - present, Botfuel (https://www.botfuel.io).
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  var Logger = require('logtown');
  
  var _require = require('botfuel-nlp-sdk'),
      Spellchecking = _require.Spellchecking;
  
  var AdapterResolver = require('./adapter-resolver');
  var BrainResolver = require('./brain-resolver');
  var NluResolver = require('./nlu-resolver');
  var DialogManager = require('./dialog-manager');
  
  var _require2 = require('./config'),
      getConfiguration = _require2.getConfiguration;
  
  var AuthenticationError = require('./errors/authentication-error');
  var DialogError = require('./errors/dialog-error');
  var ResolutionError = require('./errors/resolution-error');
  
  var _require3 = require('./utils/environment'),
      checkCredentials = _require3.checkCredentials;
  
  var MiddlewareManager = require('./middleware-manager');
  
  var logger = Logger.getLogger('Bot');
  
  /**
   * This is the bot main class that ties all the components together.
   *
   * A bot has :
   * - an {@link Adapter},
   * - a {@link Brain},
   * - a {@link Config},
   * - a {@link DialogManager},
   * - a {@link MiddlewareManager},
   * - a {@link Nlu} (Natural Language Understanding) module,
   * - an optional {@link Spellchecking} module.
   */
  
  var Bot = function () {
    function Bot(config) {
      _classCallCheck(this, Bot);
  
      this.config = getConfiguration(config);
      logger.debug('constructor', this.config);
      checkCredentials(this.config);
      this.brain = new BrainResolver(this).resolve(this.config.brain.name);
      this.spellchecking = null;
      this.nlu = new NluResolver(this).resolve(this.config.nlu.name);
      this.dm = new DialogManager(this);
      this.adapter = new AdapterResolver(this).resolve(this.config.adapter.name);
      this.middlewareManager = new MiddlewareManager(this);
    }
  
    /**
     * Initializes the bot.
     * @private
     */
  
  
    _createClass(Bot, [{
      key: 'init',
      value: function () {
        var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
          return regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  _context.next = 2;
                  return this.brain.init();
  
                case 2:
                  _context.next = 4;
                  return this.nlu.init();
  
                case 4:
                  // Spellchecking
                  if (this.config.spellchecking) {
                    if (!process.env.BOTFUEL_APP_ID || !process.env.BOTFUEL_APP_KEY) {
                      logger.error('BOTFUEL_APP_ID and BOTFUEL_APP_KEY are required for using the spellchecking service!');
                    }
                    this.spellchecking = new Spellchecking({
                      appId: process.env.BOTFUEL_APP_ID,
                      appKey: process.env.BOTFUEL_APP_KEY
                    });
                  }
  
                case 5:
                case 'end':
                  return _context.stop();
              }
            }
          }, _callee, this);
        }));
  
        function init() {
          return _ref.apply(this, arguments);
        }
  
        return init;
      }()
  
      /**
       * Handles errors. Adds a user friendly message to common errors.
       */
  
    }, {
      key: 'handleError',
      value: function handleError(error) {
        if (error instanceof AuthenticationError) {
          logger.error('Botfuel API authentication failed!');
          logger.error('Please check your app’s credentials and that its plan limits haven’t been reached on https://api.botfuel.io');
        } else if (error instanceof ResolutionError) {
          logger.error('Could not resolve \'' + error.name + '\'');
        } else if (error instanceof DialogError) {
          logger.error('Could not execute dialog \'' + error.name + '\'');
        }
        throw error;
      }
  
      /**
       * Runs the bot.
       */
  
    }, {
      key: 'run',
      value: function () {
        var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
          return regeneratorRuntime.wrap(function _callee2$(_context2) {
            while (1) {
              switch (_context2.prev = _context2.next) {
                case 0:
                  logger.debug('run');
                  _context2.prev = 1;
                  _context2.next = 4;
                  return this.init();
  
                case 4:
                  _context2.next = 6;
                  return this.adapter.run();
  
                case 6:
                  _context2.next = 11;
                  break;
  
                case 8:
                  _context2.prev = 8;
                  _context2.t0 = _context2['catch'](1);
  
                  this.handleError(_context2.t0);
  
                case 11:
                case 'end':
                  return _context2.stop();
              }
            }
          }, _callee2, this, [[1, 8]]);
        }));
  
        function run() {
          return _ref2.apply(this, arguments);
        }
  
        return run;
      }()
  
      /**
       * Plays user messages (only available with the TestAdapter).
       */
  
    }, {
      key: 'play',
      value: function () {
        var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(userMessages) {
          return regeneratorRuntime.wrap(function _callee3$(_context3) {
            while (1) {
              switch (_context3.prev = _context3.next) {
                case 0:
                  logger.debug('play', userMessages);
                  _context3.prev = 1;
                  _context3.next = 4;
                  return this.init();
  
                case 4:
                  _context3.next = 6;
                  return this.adapter.play(userMessages);
  
                case 6:
                  _context3.next = 11;
                  break;
  
                case 8:
                  _context3.prev = 8;
                  _context3.t0 = _context3['catch'](1);
  
                  this.handleError(_context3.t0);
  
                case 11:
                case 'end':
                  return _context3.stop();
              }
            }
          }, _callee3, this, [[1, 8]]);
        }));
  
        function play(_x) {
          return _ref3.apply(this, arguments);
        }
  
        return play;
      }()
  
      /**
       * Cleans the bot brain.
       */
  
    }, {
      key: 'clean',
      value: function () {
        var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
          return regeneratorRuntime.wrap(function _callee4$(_context4) {
            while (1) {
              switch (_context4.prev = _context4.next) {
                case 0:
                  logger.debug('clean');
                  _context4.prev = 1;
                  _context4.next = 4;
                  return this.brain.init();
  
                case 4:
                  _context4.next = 6;
                  return this.brain.clean();
  
                case 6:
                  _context4.next = 11;
                  break;
  
                case 8:
                  _context4.prev = 8;
                  _context4.t0 = _context4['catch'](1);
  
                  this.handleError(_context4.t0);
  
                case 11:
                case 'end':
                  return _context4.stop();
              }
            }
          }, _callee4, this, [[1, 8]]);
        }));
  
        function clean() {
          return _ref4.apply(this, arguments);
        }
  
        return clean;
      }()
  
      /**
       * Handles a user message.
       */
  
    }, {
      key: 'handleMessage',
      value: function () {
        var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7(userMessage) {
          var _this = this;
  
          var botMessages, contextIn, contextOut;
          return regeneratorRuntime.wrap(function _callee7$(_context7) {
            while (1) {
              switch (_context7.prev = _context7.next) {
                case 0:
                  botMessages = [];
  
  
                  logger.debug('handleMessage', userMessage);
  
                  contextIn = {
                    user: userMessage.user,
                    brain: this.brain,
                    userMessage: userMessage,
                    config: this.config
                  };
                  _context7.next = 5;
                  return this.middlewareManager.in(contextIn, _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
                    return regeneratorRuntime.wrap(function _callee5$(_context5) {
                      while (1) {
                        switch (_context5.prev = _context5.next) {
                          case 0:
                            _context5.next = 2;
                            return _this.respond(userMessage);
  
                          case 2:
                            botMessages = _context5.sent;
  
                          case 3:
                          case 'end':
                            return _context5.stop();
                        }
                      }
                    }, _callee5, _this);
                  })));
  
                case 5:
                  contextOut = {
                    user: userMessage.user,
                    brain: this.brain,
                    botMessages: botMessages,
                    config: this.config,
                    userMessage: userMessage
                  };
                  _context7.next = 8;
                  return this.middlewareManager.out(contextOut, _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {
                    return regeneratorRuntime.wrap(function _callee6$(_context6) {
                      while (1) {
                        switch (_context6.prev = _context6.next) {
                          case 0:
                          case 'end':
                            return _context6.stop();
                        }
                      }
                    }, _callee6, _this);
                  })));
  
                case 8:
                  return _context7.abrupt('return', botMessages);
  
                case 9:
                case 'end':
                  return _context7.stop();
              }
            }
          }, _callee7, this);
        }));
  
        function handleMessage(_x2) {
          return _ref5.apply(this, arguments);
        }
  
        return handleMessage;
      }()
  
      /**
       * Responds to the user.
       */
  
    }, {
      key: 'respond',
      value: function () {
        var _ref8 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8(userMessage) {
          return regeneratorRuntime.wrap(function _callee8$(_context8) {
            while (1) {
              switch (_context8.prev = _context8.next) {
                case 0:
                  logger.debug('respond', userMessage);
  
                  // TODO Replace Conditional with Polymorphism (Fowler)
                  _context8.t0 = userMessage.type;
                  _context8.next = _context8.t0 === 'postback' ? 4 : _context8.t0 === 'image' ? 5 : _context8.t0 === 'text' ? 6 : 6;
                  break;
  
                case 4:
                  return _context8.abrupt('return', this.respondWhenPostback(userMessage));
  
                case 5:
                  return _context8.abrupt('return', this.respondWhenImage(userMessage));
  
                case 6:
                  return _context8.abrupt('return', this.respondWhenText(userMessage));
  
                case 7:
                case 'end':
                  return _context8.stop();
              }
            }
          }, _callee8, this);
        }));
  
        function respond(_x3) {
          return _ref8.apply(this, arguments);
        }
  
        return respond;
      }()
  
      /**
       * Computes the responses for a user message of type text.
       * @private
       */
  
    }, {
      key: 'respondWhenText',
      value: function () {
        var _ref9 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9(userMessage) {
          var sentence, _ref10, classificationResults, messageEntities, botMessages;
  
          return regeneratorRuntime.wrap(function _callee9$(_context9) {
            while (1) {
              switch (_context9.prev = _context9.next) {
                case 0:
                  logger.debug('respondWhenText', userMessage);
                  sentence = userMessage.payload.value;
                  _context9.next = 4;
                  return this.spellcheck(sentence);
  
                case 4:
                  sentence = _context9.sent;
                  _context9.next = 7;
                  return this.nlu.compute(sentence, {
                    brain: this.brain,
                    userMessage: userMessage
                  });
  
                case 7:
                  _ref10 = _context9.sent;
                  classificationResults = _ref10.classificationResults;
                  messageEntities = _ref10.messageEntities;
  
  
                  logger.debug('respondWhenText: classificationResults', classificationResults, messageEntities);
                  _context9.next = 13;
                  return this.dm.executeClassificationResults(userMessage, classificationResults, messageEntities);
  
                case 13:
                  botMessages = _context9.sent;
                  return _context9.abrupt('return', botMessages);
  
                case 15:
                case 'end':
                  return _context9.stop();
              }
            }
          }, _callee9, this);
        }));
  
        function respondWhenText(_x4) {
          return _ref9.apply(this, arguments);
        }
  
        return respondWhenText;
      }()
  
      /**
       * Computes the responses for a user message of type postback.
       * @private
       */
  
    }, {
      key: 'respondWhenPostback',
      value: function () {
        var _ref11 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee10(userMessage) {
          var dialog, botMessages;
          return regeneratorRuntime.wrap(function _callee10$(_context10) {
            while (1) {
              switch (_context10.prev = _context10.next) {
                case 0:
                  logger.debug('respondWhenPostback', userMessage);
                  dialog = {
                    name: userMessage.payload.value.dialog,
                    data: {
                      messageEntities: userMessage.payload.value.entities
                    }
                  };
                  _context10.next = 4;
                  return this.dm.executeDialog(userMessage, dialog);
  
                case 4:
                  botMessages = _context10.sent;
                  return _context10.abrupt('return', botMessages);
  
                case 6:
                case 'end':
                  return _context10.stop();
              }
            }
          }, _callee10, this);
        }));
  
        function respondWhenPostback(_x5) {
          return _ref11.apply(this, arguments);
        }
  
        return respondWhenPostback;
      }()
  
      /**
       * Computes the responses for a user message of type image.
       * @private
       */
  
    }, {
      key: 'respondWhenImage',
      value: function () {
        var _ref12 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee11(userMessage) {
          var dialog, botMessages;
          return regeneratorRuntime.wrap(function _callee11$(_context11) {
            while (1) {
              switch (_context11.prev = _context11.next) {
                case 0:
                  logger.debug('respondWhenImage', userMessage);
                  dialog = {
                    name: 'image',
                    data: {
                      url: userMessage.payload.value
                    }
                  };
                  _context11.next = 4;
                  return this.dm.executeDialog(userMessage, dialog);
  
                case 4:
                  botMessages = _context11.sent;
                  return _context11.abrupt('return', botMessages);
  
                case 6:
                case 'end':
                  return _context11.stop();
              }
            }
          }, _callee11, this);
        }));
  
        function respondWhenImage(_x6) {
          return _ref12.apply(this, arguments);
        }
  
        return respondWhenImage;
      }()
  
      /**
       * Spellchecks a sentence.
       * @param sentence - a sentence
       * @returns the spellchecked sentence
       */
  
    }, {
      key: 'spellcheck',
      value: function () {
        var _ref13 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee12(sentence) {
          var key, result;
          return regeneratorRuntime.wrap(function _callee12$(_context12) {
            while (1) {
              switch (_context12.prev = _context12.next) {
                case 0:
                  key = this.config.spellchecking;
  
  
                  logger.debug('spellcheck', sentence, key);
  
                  if (!(!key || !this.spellchecking)) {
                    _context12.next = 4;
                    break;
                  }
  
                  return _context12.abrupt('return', sentence);
  
                case 4:
                  _context12.prev = 4;
                  _context12.next = 7;
                  return this.spellchecking.compute({ sentence: sentence, key: key });
  
                case 7:
                  result = _context12.sent;
  
                  logger.debug('spellcheck: result', result);
                  return _context12.abrupt('return', result.correctSentence);
  
                case 12:
                  _context12.prev = 12;
                  _context12.t0 = _context12['catch'](4);
  
                  logger.error('spellcheck: error');
  
                  if (!(_context12.t0.statusCode === 403)) {
                    _context12.next = 17;
                    break;
                  }
  
                  throw new AuthenticationError();
  
                case 17:
                  throw _context12.t0;
  
                case 18:
                case 'end':
                  return _context12.stop();
              }
            }
          }, _callee12, this, [[4, 12]]);
        }));
  
        function spellcheck(_x7) {
          return _ref13.apply(this, arguments);
        }
  
        return spellcheck;
      }()
    }]);
  
    return Bot;
  }();
  
  module.exports = Bot;