'use strict';

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

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

var _index2 = _interopRequireDefault(_index);

var _array = require('../../array.js');

var _array2 = _interopRequireDefault(_array);

var _extent = require('../../extent.js');

var _extent2 = _interopRequireDefault(_extent);

var _obj = require('../../obj.js');

var _obj2 = _interopRequireDefault(_obj);

var _replay = require('../replay.js');

var _replay2 = _interopRequireDefault(_replay);

var _replaygroup = require('../replaygroup.js');

var _replaygroup2 = _interopRequireDefault(_replaygroup);

var _circlereplay = require('../webgl/circlereplay.js');

var _circlereplay2 = _interopRequireDefault(_circlereplay);

var _imagereplay = require('../webgl/imagereplay.js');

var _imagereplay2 = _interopRequireDefault(_imagereplay);

var _linestringreplay = require('../webgl/linestringreplay.js');

var _linestringreplay2 = _interopRequireDefault(_linestringreplay);

var _polygonreplay = require('../webgl/polygonreplay.js');

var _polygonreplay2 = _interopRequireDefault(_polygonreplay);

var _textreplay = require('../webgl/textreplay.js');

var _textreplay2 = _interopRequireDefault(_textreplay);

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

/**
 * @constructor
 * @extends {ol.render.ReplayGroup}
 * @param {number} tolerance Tolerance.
 * @param {ol.Extent} maxExtent Max extent.
 * @param {number=} opt_renderBuffer Render buffer.
 * @struct
 */
var _ol_render_webgl_ReplayGroup_ = function (tolerance, maxExtent, opt_renderBuffer) {
  _replaygroup2.default.call(this);

  /**
   * @type {ol.Extent}
   * @private
   */
  this.maxExtent_ = maxExtent;

  /**
   * @type {number}
   * @private
   */
  this.tolerance_ = tolerance;

  /**
   * @type {number|undefined}
   * @private
   */
  this.renderBuffer_ = opt_renderBuffer;

  /**
   * @private
   * @type {!Object.<string,
   *        Object.<ol.render.ReplayType, ol.render.webgl.Replay>>}
   */
  this.replaysByZIndex_ = {};
};

_index2.default.inherits(_ol_render_webgl_ReplayGroup_, _replaygroup2.default);

/**
 * @param {ol.style.Style} style Style.
 * @param {boolean} group Group with previous replay.
 */
_ol_render_webgl_ReplayGroup_.prototype.addDeclutter = function (style, group) {};

/**
 * @param {ol.webgl.Context} context WebGL context.
 * @return {function()} Delete resources function.
 */
_ol_render_webgl_ReplayGroup_.prototype.getDeleteResourcesFunction = function (context) {
  var functions = [];
  var zKey;
  for (zKey in this.replaysByZIndex_) {
    var replays = this.replaysByZIndex_[zKey];
    var replayKey;
    for (replayKey in replays) {
      functions.push(replays[replayKey].getDeleteResourcesFunction(context));
    }
  }
  return function () {
    var length = functions.length;
    var result;
    for (var i = 0; i < length; i++) {
      result = functions[i].apply(this, arguments);
    }
    return result;
  };
};

/**
 * @param {ol.webgl.Context} context Context.
 */
_ol_render_webgl_ReplayGroup_.prototype.finish = function (context) {
  var zKey;
  for (zKey in this.replaysByZIndex_) {
    var replays = this.replaysByZIndex_[zKey];
    var replayKey;
    for (replayKey in replays) {
      replays[replayKey].finish(context);
    }
  }
};

/**
 * @inheritDoc
 */
_ol_render_webgl_ReplayGroup_.prototype.getReplay = function (zIndex, replayType) {
  var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
  var replays = this.replaysByZIndex_[zIndexKey];
  if (replays === undefined) {
    replays = {};
    this.replaysByZIndex_[zIndexKey] = replays;
  }
  var replay = replays[replayType];
  if (replay === undefined) {
    /**
     * @type {Function}
     */
    var Constructor = _ol_render_webgl_ReplayGroup_.BATCH_CONSTRUCTORS_[replayType];
    replay = new Constructor(this.tolerance_, this.maxExtent_);
    replays[replayType] = replay;
  }
  return replay;
};

/**
 * @inheritDoc
 */
_ol_render_webgl_ReplayGroup_.prototype.isEmpty = function () {
  return _obj2.default.isEmpty(this.replaysByZIndex_);
};

/**
 * @param {ol.webgl.Context} context Context.
 * @param {ol.Coordinate} center Center.
 * @param {number} resolution Resolution.
 * @param {number} rotation Rotation.
 * @param {ol.Size} size Size.
 * @param {number} pixelRatio Pixel ratio.
 * @param {number} opacity Global opacity.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *  to skip.
 */
_ol_render_webgl_ReplayGroup_.prototype.replay = function (context, center, resolution, rotation, size, pixelRatio, opacity, skippedFeaturesHash) {
  /** @type {Array.<number>} */
  var zs = Object.keys(this.replaysByZIndex_).map(Number);
  zs.sort(_array2.default.numberSafeCompareFunction);

  var i, ii, j, jj, replays, replay;
  for (i = 0, ii = zs.length; i < ii; ++i) {
    replays = this.replaysByZIndex_[zs[i].toString()];
    for (j = 0, jj = _replay2.default.ORDER.length; j < jj; ++j) {
      replay = replays[_replay2.default.ORDER[j]];
      if (replay !== undefined) {
        replay.replay(context, center, resolution, rotation, size, pixelRatio, opacity, skippedFeaturesHash, undefined, false);
      }
    }
  }
};

/**
 * @private
 * @param {ol.webgl.Context} context Context.
 * @param {ol.Coordinate} center Center.
 * @param {number} resolution Resolution.
 * @param {number} rotation Rotation.
 * @param {ol.Size} size Size.
 * @param {number} pixelRatio Pixel ratio.
 * @param {number} opacity Global opacity.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *  to skip.
 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
 * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
 * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
 *  this extent are checked.
 * @return {T|undefined} Callback result.
 * @template T
 */
_ol_render_webgl_ReplayGroup_.prototype.replayHitDetection_ = function (context, center, resolution, rotation, size, pixelRatio, opacity, skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) {
  /** @type {Array.<number>} */
  var zs = Object.keys(this.replaysByZIndex_).map(Number);
  zs.sort(function (a, b) {
    return b - a;
  });

  var i, ii, j, replays, replay, result;
  for (i = 0, ii = zs.length; i < ii; ++i) {
    replays = this.replaysByZIndex_[zs[i].toString()];
    for (j = _replay2.default.ORDER.length - 1; j >= 0; --j) {
      replay = replays[_replay2.default.ORDER[j]];
      if (replay !== undefined) {
        result = replay.replay(context, center, resolution, rotation, size, pixelRatio, opacity, skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent);
        if (result) {
          return result;
        }
      }
    }
  }
  return undefined;
};

/**
 * @param {ol.Coordinate} coordinate Coordinate.
 * @param {ol.webgl.Context} context Context.
 * @param {ol.Coordinate} center Center.
 * @param {number} resolution Resolution.
 * @param {number} rotation Rotation.
 * @param {ol.Size} size Size.
 * @param {number} pixelRatio Pixel ratio.
 * @param {number} opacity Global opacity.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *  to skip.
 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} callback Feature callback.
 * @return {T|undefined} Callback result.
 * @template T
 */
_ol_render_webgl_ReplayGroup_.prototype.forEachFeatureAtCoordinate = function (coordinate, context, center, resolution, rotation, size, pixelRatio, opacity, skippedFeaturesHash, callback) {
  var gl = context.getGL();
  gl.bindFramebuffer(gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());

  /**
   * @type {ol.Extent}
   */
  var hitExtent;
  if (this.renderBuffer_ !== undefined) {
    // build an extent around the coordinate, so that only features that
    // intersect this extent are checked
    hitExtent = _extent2.default.buffer(_extent2.default.createOrUpdateFromCoordinate(coordinate), resolution * this.renderBuffer_);
  }

  return this.replayHitDetection_(context, coordinate, resolution, rotation, _ol_render_webgl_ReplayGroup_.HIT_DETECTION_SIZE_, pixelRatio, opacity, skippedFeaturesHash,
  /**
   * @param {ol.Feature|ol.render.Feature} feature Feature.
   * @return {?} Callback result.
   */
  function (feature) {
    var imageData = new Uint8Array(4);
    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);

    if (imageData[3] > 0) {
      var result = callback(feature);
      if (result) {
        return result;
      }
    }
  }, true, hitExtent);
};

/**
 * @param {ol.Coordinate} coordinate Coordinate.
 * @param {ol.webgl.Context} context Context.
 * @param {ol.Coordinate} center Center.
 * @param {number} resolution Resolution.
 * @param {number} rotation Rotation.
 * @param {ol.Size} size Size.
 * @param {number} pixelRatio Pixel ratio.
 * @param {number} opacity Global opacity.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *  to skip.
 * @return {boolean} Is there a feature at the given coordinate?
 */
_ol_render_webgl_ReplayGroup_.prototype.hasFeatureAtCoordinate = function (coordinate, context, center, resolution, rotation, size, pixelRatio, opacity, skippedFeaturesHash) {
  var gl = context.getGL();
  gl.bindFramebuffer(gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());

  var hasFeature = this.replayHitDetection_(context, coordinate, resolution, rotation, _ol_render_webgl_ReplayGroup_.HIT_DETECTION_SIZE_, pixelRatio, opacity, skippedFeaturesHash,
  /**
   * @param {ol.Feature|ol.render.Feature} feature Feature.
   * @return {boolean} Is there a feature?
   */
  function (feature) {
    var imageData = new Uint8Array(4);
    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
    return imageData[3] > 0;
  }, false);

  return hasFeature !== undefined;
};

/**
 * @const
 * @private
 * @type {Array.<number>}
 */
_ol_render_webgl_ReplayGroup_.HIT_DETECTION_SIZE_ = [1, 1];

/**
 * @const
 * @private
 * @type {Object.<ol.render.ReplayType,
 *                function(new: ol.render.webgl.Replay, number,
 *                ol.Extent)>}
 */
_ol_render_webgl_ReplayGroup_.BATCH_CONSTRUCTORS_ = {
  'Circle': _circlereplay2.default,
  'Image': _imagereplay2.default,
  'LineString': _linestringreplay2.default,
  'Polygon': _polygonreplay2.default,
  'Text': _textreplay2.default
};
exports.default = _ol_render_webgl_ReplayGroup_;
module.exports = exports['default'];