'use strict';

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

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);

var _promise = require('babel-runtime/core-js/promise');

var _promise2 = _interopRequireDefault(_promise);

var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var _iterall = require('iterall');

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

class AsyncIterableRingBuffer {
  constructor(size) {
    this.size = size;
    this.buffer = [];
    this._startItem = 0;
    this._endItem = 0;
    this._pushResolves = [];
  }

  all() {
    return [...this.buffer];
  }

  allWithCursor() {
    return this.buffer.map((item, i) => ({
      item,
      cursor: this._startItem + i
    }));
  }

  getNextCursor(cursor) {
    if (cursor !== null && cursor >= this._startItem) {
      return cursor + 1;
    } else {
      return this._startItem;
    }
  }

  getLastCursor() {
    return this._endItem;
  }

  get(cursor) {
    var _this = this;

    return (0, _asyncToGenerator3.default)(function* () {
      if (_this._endItem > cursor) {
        const adjustedCursor = cursor - _this._startItem;
        return _this.buffer[adjustedCursor];
      } else {
        return new _promise2.default(function (resolve) {
          _this._pushResolves.push(resolve);
        });
      }
    })();
  }

  length() {
    return this.buffer.length;
  }

  push(item) {
    this.buffer.push(item);
    this._endItem++;
    this._pushResolves.forEach(resolve => resolve(item));
    this._pushResolves = [];

    if (this.buffer.length > this.size) {
      this.buffer.shift();
      this._startItem++;
    }
  }

  filterWithCursor(filter) {
    let cursor;
    const items = this.buffer.filter((item, i) => {
      cursor = this._startItem + i;
      return filter(item, cursor);
    });
    return {
      cursor,
      items
    };
  }

  getIterator(cursor) {
    let buffer = this;
    let iterableCursor = cursor;
    return {
      next() {
        return (0, _asyncToGenerator3.default)(function* () {
          iterableCursor = buffer.getNextCursor(iterableCursor);
          const value = yield buffer.get(iterableCursor);
          return {
            value: (0, _extends3.default)({}, value, {
              cursor: iterableCursor
            }),
            done: false
          };
        })();
      },

      [_iterall.$$asyncIterator]() {
        return this;
      }
    };
  }
}
exports.default = AsyncIterableRingBuffer;