'use strict';

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

var _index = require('./index.js');

var _index2 = _interopRequireDefault(_index);

var _tilestate = require('./tilestate.js');

var _tilestate2 = _interopRequireDefault(_tilestate);

var _events = require('./events.js');

var _events2 = _interopRequireDefault(_events);

var _eventtype = require('./events/eventtype.js');

var _eventtype2 = _interopRequireDefault(_eventtype);

var _priorityqueue = require('./structs/priorityqueue.js');

var _priorityqueue2 = _interopRequireDefault(_priorityqueue);

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

/**
 * @constructor
 * @extends {ol.structs.PriorityQueue.<Array>}
 * @param {ol.TilePriorityFunction} tilePriorityFunction
 *     Tile priority function.
 * @param {function(): ?} tileChangeCallback
 *     Function called on each tile change event.
 * @struct
 */
var _ol_TileQueue_ = function (tilePriorityFunction, tileChangeCallback) {

  _priorityqueue2.default.call(this,
  /**
   * @param {Array} element Element.
   * @return {number} Priority.
   */
  function (element) {
    return tilePriorityFunction.apply(null, element);
  },
  /**
   * @param {Array} element Element.
   * @return {string} Key.
   */
  function (element) {
    return (/** @type {ol.Tile} */element[0].getKey()
    );
  });

  /**
   * @private
   * @type {function(): ?}
   */
  this.tileChangeCallback_ = tileChangeCallback;

  /**
   * @private
   * @type {number}
   */
  this.tilesLoading_ = 0;

  /**
   * @private
   * @type {!Object.<string,boolean>}
   */
  this.tilesLoadingKeys_ = {};
};

_index2.default.inherits(_ol_TileQueue_, _priorityqueue2.default);

/**
 * @inheritDoc
 */
_ol_TileQueue_.prototype.enqueue = function (element) {
  var added = _priorityqueue2.default.prototype.enqueue.call(this, element);
  if (added) {
    var tile = element[0];
    _events2.default.listen(tile, _eventtype2.default.CHANGE, this.handleTileChange, this);
  }
  return added;
};

/**
 * @return {number} Number of tiles loading.
 */
_ol_TileQueue_.prototype.getTilesLoading = function () {
  return this.tilesLoading_;
};

/**
 * @param {ol.events.Event} event Event.
 * @protected
 */
_ol_TileQueue_.prototype.handleTileChange = function (event) {
  var tile = /** @type {ol.Tile} */event.target;
  var state = tile.getState();
  if (state === _tilestate2.default.LOADED || state === _tilestate2.default.ERROR || state === _tilestate2.default.EMPTY || state === _tilestate2.default.ABORT) {
    _events2.default.unlisten(tile, _eventtype2.default.CHANGE, this.handleTileChange, this);
    var tileKey = tile.getKey();
    if (tileKey in this.tilesLoadingKeys_) {
      delete this.tilesLoadingKeys_[tileKey];
      --this.tilesLoading_;
    }
    this.tileChangeCallback_();
  }
};

/**
 * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
 * @param {number} maxNewLoads Maximum number of new tiles to load.
 */
_ol_TileQueue_.prototype.loadMoreTiles = function (maxTotalLoading, maxNewLoads) {
  var newLoads = 0;
  var abortedTiles = false;
  var state, tile, tileKey;
  while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads && this.getCount() > 0) {
    tile = /** @type {ol.Tile} */this.dequeue()[0];
    tileKey = tile.getKey();
    state = tile.getState();
    if (state === _tilestate2.default.ABORT) {
      abortedTiles = true;
    } else if (state === _tilestate2.default.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
      this.tilesLoadingKeys_[tileKey] = true;
      ++this.tilesLoading_;
      ++newLoads;
      tile.load();
    }
  }
  if (newLoads === 0 && abortedTiles) {
    // Do not stop the render loop when all wanted tiles were aborted due to
    // a small, saturated tile cache.
    this.tileChangeCallback_();
  }
};
exports.default = _ol_TileQueue_;
module.exports = exports['default'];