text: "use strict";
  
  var _stringify = require("babel-runtime/core-js/json/stringify");
  
  var _stringify2 = _interopRequireDefault(_stringify);
  
  var _regenerator = require("babel-runtime/regenerator");
  
  var _regenerator2 = _interopRequireDefault(_regenerator);
  
  var _map = require("babel-runtime/core-js/map");
  
  var _map2 = _interopRequireDefault(_map);
  
  var _getPrototypeOf = require("babel-runtime/core-js/object/get-prototype-of");
  
  var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  
  var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
  
  var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  
  var _createClass2 = require("babel-runtime/helpers/createClass");
  
  var _createClass3 = _interopRequireDefault(_createClass2);
  
  var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
  
  var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  
  var _inherits2 = require("babel-runtime/helpers/inherits");
  
  var _inherits3 = _interopRequireDefault(_inherits2);
  
  var _promise = require("babel-runtime/core-js/promise");
  
  var _promise2 = _interopRequireDefault(_promise);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  var __awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
      return new (P || (P = _promise2.default))(function (resolve, reject) {
          function fulfilled(value) {
              try {
                  step(generator.next(value));
              } catch (e) {
                  reject(e);
              }
          }
          function rejected(value) {
              try {
                  step(generator["throw"](value));
              } catch (e) {
                  reject(e);
              }
          }
          function step(result) {
              result.done ? resolve(result.value) : new P(function (resolve) {
                  resolve(result.value);
              }).then(fulfilled, rejected);
          }
          step((generator = generator.apply(thisArg, _arguments || [])).next());
      });
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  var events_1 = require("events");
  var logger_1 = require("../logger");
  var message_1 = require("../message");
  var FormData = require("isomorphic-form-data");
  var log = logger_1.Logger.scope('Messages');
  /**
   * Represents the collection of messages in a channel
   */
  
  var Messages = function (_events_1$EventEmitte) {
      (0, _inherits3.default)(Messages, _events_1$EventEmitte);
  
      function Messages(channel, services) {
          (0, _classCallCheck3.default)(this, Messages);
  
          var _this = (0, _possibleConstructorReturn3.default)(this, (Messages.__proto__ || (0, _getPrototypeOf2.default)(Messages)).call(this));
  
          _this.channel = channel;
          _this.services = services;
          _this.messagesByIndex = new _map2.default();
          _this.messagesListPromise = null;
          return _this;
      }
      /**
       * Subscribe to the Messages Event Stream
       * @param {String} name - The name of Sync object for the Messages resource.
       * @returns {Promise}
       */
  
  
      (0, _createClass3.default)(Messages, [{
          key: "subscribe",
          value: function subscribe(name) {
              var _this2 = this;
  
              return this.messagesListPromise = this.messagesListPromise || this.services.syncClient.list({ id: name, mode: 'open_existing' }).then(function (list) {
                  list.on('itemAdded', function (args) {
                      var message = new message_1.Message(_this2.channel, _this2.services, args.item.index, args.item.value);
                      if (_this2.messagesByIndex.has(message.index)) {
                          log.debug('Message arrived, but already known and ignored', _this2.channel.sid, message.index);
                          return;
                      }
                      _this2.messagesByIndex.set(message.index, message);
                      message.on('updated', function (args) {
                          return _this2.emit('messageUpdated', args);
                      });
                      _this2.emit('messageAdded', message);
                  });
                  list.on('itemRemoved', function (args) {
                      var index = args.index;
                      if (_this2.messagesByIndex.has(index)) {
                          var message = _this2.messagesByIndex.get(index);
                          _this2.messagesByIndex.delete(message.index);
                          message.removeAllListeners('updated');
                          _this2.emit('messageRemoved', message);
                      }
                  });
                  list.on('itemUpdated', function (args) {
                      var message = _this2.messagesByIndex.get(args.item.index);
                      if (message) {
                          message._update(args.item.value);
                      }
                  });
                  return list;
              }).catch(function (err) {
                  _this2.messagesListPromise = null;
                  if (_this2.services.syncClient.connectionState != 'disconnected') {
                      log.error('Failed to get messages object for channel', _this2.channel.sid, err);
                  }
                  log.debug('ERROR: Failed to get messages object for channel', _this2.channel.sid, err);
                  throw err;
              });
          }
      }, {
          key: "unsubscribe",
          value: function unsubscribe() {
              return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee() {
                  var entity;
                  return _regenerator2.default.wrap(function _callee$(_context) {
                      while (1) {
                          switch (_context.prev = _context.next) {
                              case 0:
                                  if (!this.messagesListPromise) {
                                      _context.next = 6;
                                      break;
                                  }
  
                                  _context.next = 3;
                                  return this.messagesListPromise;
  
                              case 3:
                                  entity = _context.sent;
  
                                  entity.close();
                                  this.messagesListPromise = null;
  
                              case 6:
                              case "end":
                                  return _context.stop();
                          }
                      }
                  }, _callee, this);
              }));
          }
          /**
           * Send Message to the channel
           * @param {String} message - Message to post
           * @param {Object} attributes Message attributes
           * @returns Returns promise which can fail
           */
  
      }, {
          key: "send",
          value: function send(message) {
              var attributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  
              return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee2() {
                  return _regenerator2.default.wrap(function _callee2$(_context2) {
                      while (1) {
                          switch (_context2.prev = _context2.next) {
                              case 0:
                                  log.debug('Sending text message', message, attributes);
  
                                  if (!(attributes.constructor !== Object)) {
                                      _context2.next = 3;
                                      break;
                                  }
  
                                  throw new Error('Attributes must be a valid JSON object');
  
                              case 3:
                                  return _context2.abrupt("return", this.services.session.addCommand('sendMessage', {
                                      channelSid: this.channel.sid,
                                      text: message,
                                      attributes: (0, _stringify2.default)(attributes)
                                  }));
  
                              case 4:
                              case "end":
                                  return _context2.stop();
                          }
                      }
                  }, _callee2, this);
              }));
          }
          /**
           * Send Media Message to the channel
           * @param {FormData | Channel#SendMediaOptions} mediaContent - Media content to post
           * @param {Object} attributes Message attributes
           * @returns Returns promise which can fail
           */
  
      }, {
          key: "sendMedia",
          value: function sendMedia(mediaContent) {
              var attributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  
              return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator2.default.mark(function _callee3() {
                  var media, mediaOptions;
                  return _regenerator2.default.wrap(function _callee3$(_context3) {
                      while (1) {
                          switch (_context3.prev = _context3.next) {
                              case 0:
                                  log.debug('Sending media message', mediaContent, attributes);
  
                                  if (!(attributes.constructor !== Object)) {
                                      _context3.next = 3;
                                      break;
                                  }
  
                                  throw new Error('Attributes must be a valid JSON object');
  
                              case 3:
                                  media = void 0;
  
                                  if (!(mediaContent instanceof FormData)) {
                                      _context3.next = 11;
                                      break;
                                  }
  
                                  log.debug('Sending media message as FormData', mediaContent, attributes);
                                  _context3.next = 8;
                                  return this.services.mcsClient.postFormData(mediaContent);
  
                              case 8:
                                  media = _context3.sent;
                                  _context3.next = 18;
                                  break;
  
                              case 11:
                                  log.debug('Sending media message as SendMediaOptions', mediaContent, attributes);
                                  mediaOptions = mediaContent;
  
                                  if (!(!mediaOptions.contentType || !mediaOptions.media)) {
                                      _context3.next = 15;
                                      break;
                                  }
  
                                  throw new Error('Media content <Channel#SendMediaOptions> must contain non-empty contentType and media');
  
                              case 15:
                                  _context3.next = 17;
                                  return this.services.mcsClient.post(mediaOptions.contentType, mediaOptions.media);
  
                              case 17:
                                  media = _context3.sent;
  
                              case 18:
                                  return _context3.abrupt("return", this.services.session.addCommand('sendMediaMessage', {
                                      channelSid: this.channel.sid,
                                      mediaSid: media.sid,
                                      attributes: (0, _stringify2.default)(attributes)
                                  }));
  
                              case 19:
                              case "end":
                                  return _context3.stop();
                          }
                      }
                  }, _callee3, this);
              }));
          }
          /**
           * Returns messages from channel using paginator interface
           * @param {Number} [pageSize] Number of messages to return in single chunk. By default it's 30.
           * @param {String} [anchor] Most early message id which is already known, or 'end' by default
           * @param {String} [direction] Pagination order 'backwards' or 'forward', or 'forward' by default
           * @returns {Promise<Paginator<Message>>} last page of messages by default
           */
  
      }, {
          key: "getMessages",
          value: function getMessages(pageSize, anchor, direction) {
              anchor = typeof anchor !== 'undefined' ? anchor : 'end';
              direction = direction || 'backwards';
              return this._getMessages(pageSize, anchor, direction);
          }
      }, {
          key: "wrapPaginator",
          value: function wrapPaginator(order, page, op) {
              var _this3 = this;
  
              // We should swap next and prev page here, because of misfit of Sync and Chat paging conceptions
              var shouldReverse = order === 'desc';
              var np = function np() {
                  return page.nextPage().then(function (x) {
                      return _this3.wrapPaginator(order, x, op);
                  });
              };
              var pp = function pp() {
                  return page.prevPage().then(function (x) {
                      return _this3.wrapPaginator(order, x, op);
                  });
              };
              return op(page.items).then(function (items) {
                  return {
                      items: items.sort(function (x, y) {
                          return x.index - y.index;
                      }),
                      hasPrevPage: shouldReverse ? page.hasNextPage : page.hasPrevPage,
                      hasNextPage: shouldReverse ? page.hasPrevPage : page.hasNextPage,
                      prevPage: shouldReverse ? np : pp,
                      nextPage: shouldReverse ? pp : np
                  };
              });
          }
      }, {
          key: "_upsertMessage",
          value: function _upsertMessage(index, value) {
              var _this4 = this;
  
              var cachedMessage = this.messagesByIndex.get(index);
              if (cachedMessage) {
                  return cachedMessage;
              }
              var message = new message_1.Message(this.channel, this.services, index, value);
              this.messagesByIndex.set(message.index, message);
              message.on('updated', function (args) {
                  return _this4.emit('messageUpdated', args);
              });
              return message;
          }
          /**
           * Returns last messages from channel
           * @param {Number} [pageSize] Number of messages to return in single chunk. By default it's 30.
           * @param {String} [anchor] Most early message id which is already known, or 'end' by default
           * @param {String} [direction] Pagination order 'backwards' or 'forward', or 'forward' by default
           * @returns {Promise<SyncPaginator<Message>>} last page of messages by default
           * @private
           */
  
      }, {
          key: "_getMessages",
          value: function _getMessages(pageSize, anchor, direction) {
              var _this5 = this;
  
              anchor = typeof anchor !== 'undefined' ? anchor : 'end';
              pageSize = pageSize || 30;
              var order = direction === 'backwards' ? 'desc' : 'asc';
              return this.messagesListPromise.then(function (messagesList) {
                  return messagesList.getItems({
                      from: anchor !== 'end' ? anchor : void 0,
                      pageSize: pageSize,
                      order: order
                  });
              }).then(function (page) {
                  return _this5.wrapPaginator(order, page, function (items) {
                      return _promise2.default.all(items.map(function (item) {
                          return _this5._upsertMessage(item.index, item.value);
                      }));
                  });
              });
          }
      }]);
      return Messages;
  }(events_1.EventEmitter);
  
  exports.Messages = Messages;