'use strict';

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

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

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

var ERROR_STATE = 'error';
var WAITING_STATE = 'waiting';
var SENDING_STATE = 'sending';
var SENT_STATE = 'sent';

var StreamQueue = function () {
  function StreamQueue(_ref) {
    var config = _ref.config,
        kinesis = _ref.kinesis;
    (0, _classCallCheck3.default)(this, StreamQueue);

    this.config = config;
    this.kinesis = kinesis;
    this.timeout = null;
    this.pageQueue = [];
    this._addPage();
    this._scheduleSendRecords();
  }

  (0, _createClass3.default)(StreamQueue, [{
    key: 'push',
    value: function push(eventType, data) {
      var event = this._buildRecord(eventType, data);
      if (this._canEnqueueToPage(this._lastPage())) {
        this._lastPage().data.push(event);
        this._sendIfLastPageFull();
      } else {
        this._sendRecords();
        this._addPage();
        this._lastPage().data.push(event);
      }
      return true;
    }

    // =============
    // PRIVATE
    // =============

  }, {
    key: '_scheduleSendRecords',
    value: function _scheduleSendRecords() {
      clearTimeout(this.timeout);
      this.timeout = setTimeout(this._sendRecords.bind(this), this.config.sendRecordsTimeout);
    }
  }, {
    key: '_sendIfLastPageFull',
    value: function _sendIfLastPageFull() {
      if (this._lastPage().data.length === this.config.maxPageSize) {
        this._sendRecords();
        this._addPage();
      }
    }
  }, {
    key: '_canEnqueueToPage',
    value: function _canEnqueueToPage(page) {
      return page.status === WAITING_STATE && page.data.length < this.config.maxPageSize;
    }
  }, {
    key: '_lastPage',
    value: function _lastPage() {
      return this.pageQueue[this.pageQueue.length - 1];
    }
  }, {
    key: '_addPage',
    value: function _addPage() {
      this.pageQueue.push({ status: WAITING_STATE, data: [] });
    }
  }, {
    key: '_buildRecord',
    value: function _buildRecord(eventType, data) {
      var builder = this.config.eventTypes[eventType];

      if (typeof builder !== 'function') {
        throw new Error('Unable to retrieve a builder function for event type: ' + eventType);
      }

      try {
        return builder(data);
      } catch (e) {
        throw new Error('Unable to build a record for data: ' + JSON.stringify(data) + '\n' + e);
      }
    }
  }, {
    key: '_canSendPage',
    value: function _canSendPage(page) {
      return (page.status === WAITING_STATE || page.status === ERROR_STATE) && page.data.length;
    }
  }, {
    key: '_sendRecords',
    value: function _sendRecords() {
      var _this = this;

      this.pageQueue.forEach(function (page, i) {
        if (!_this._canSendPage(page)) return;

        var params = {
          Records: page.data,
          StreamName: _this.config.stream
        };

        _this.pageQueue[i].status = SENDING_STATE;

        _this.kinesis.putRecords(params, function (err, data) {
          if (err) {
            _this.pageQueue[i].status = ERROR_STATE;
            // eslint-disable-next-line no-console
            console.error('KINESIS STREAM ' + _this.config.stream + ' ERROR: ', err);
          } else {
            _this.pageQueue[i].status = SENT_STATE;
            // eslint-disable-next-line no-console
            console.log('KINESIS STREAM ' + _this.config.stream + ' STATUS: ', page.data.length + ' items sent successfully');
          }
        });
      });
      this._scheduleSendRecords();
    }
  }]);
  return StreamQueue;
}();

exports.default = StreamQueue;