'use strict';

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

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

var _core = require('../../core');

var _luma = require('luma.gl');

var _mathUtils = require('./../../core/utils/math-utils');

var _log = require('./../../core/utils/log');

var _log2 = _interopRequireDefault(_log);

var _screenGridLayerVertex = require('./screen-grid-layer-vertex.glsl');

var _screenGridLayerVertex2 = _interopRequireDefault(_screenGridLayerVertex);

var _screenGridLayerFragment = require('./screen-grid-layer-fragment.glsl');

var _screenGridLayerFragment2 = _interopRequireDefault(_screenGridLayerFragment);

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

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

var defaultColorRange = _core.experimental.defaultColorRange,
    quantizeScale = _core.experimental.quantizeScale;


var defaultProps = {
  cellSizePixels: 100,

  colorDomain: null,
  colorRange: defaultColorRange,

  getPosition: function getPosition(d) {
    return d.position;
  },
  getWeight: function getWeight(d) {
    return 1;
  },

  // deprecated
  minColor: null,
  maxColor: null
};

var ScreenGridLayer = function (_Layer) {
  _inherits(ScreenGridLayer, _Layer);

  function ScreenGridLayer() {
    _classCallCheck(this, ScreenGridLayer);

    return _possibleConstructorReturn(this, (ScreenGridLayer.__proto__ || Object.getPrototypeOf(ScreenGridLayer)).apply(this, arguments));
  }

  _createClass(ScreenGridLayer, [{
    key: 'getShaders',
    value: function getShaders() {
      return { vs: _screenGridLayerVertex2.default, fs: _screenGridLayerFragment2.default, modules: ['picking'] }; // 'project' module added by default.
    }
  }, {
    key: 'initializeState',
    value: function initializeState() {
      var attributeManager = this.getAttributeManager();
      var gl = this.context.gl;


      if (this.props.minColor || this.props.maxColor) {
        _log2.default.deprecated('minColor and maxColor', 'colorRange, colorDomain')();
      }
      /* eslint-disable max-len */
      attributeManager.addInstanced({
        instancePositions: { size: 3, update: this.calculateInstancePositions },
        instanceColors: {
          size: 4,
          type: _luma.GL.UNSIGNED_BYTE,
          transition: true,
          accessor: ['getPosition', 'getWeight'],
          update: this.calculateInstanceColors
        }
      });
      /* eslint-disable max-len */

      this.setState({ model: this._getModel(gl) });
    }
  }, {
    key: 'shouldUpdateState',
    value: function shouldUpdateState(_ref) {
      var changeFlags = _ref.changeFlags;

      return changeFlags.somethingChanged;
    }
  }, {
    key: 'updateState',
    value: function updateState(_ref2) {
      var oldProps = _ref2.oldProps,
          props = _ref2.props,
          changeFlags = _ref2.changeFlags;

      _get(ScreenGridLayer.prototype.__proto__ || Object.getPrototypeOf(ScreenGridLayer.prototype), 'updateState', this).call(this, { props: props, oldProps: oldProps, changeFlags: changeFlags });
      var cellSizeChanged = props.cellSizePixels !== oldProps.cellSizePixels;

      if (cellSizeChanged || changeFlags.viewportChanged) {
        this.updateCell();
      }
    }
  }, {
    key: 'draw',
    value: function draw(_ref3) {
      var uniforms = _ref3.uniforms;
      var _props = this.props,
          minColor = _props.minColor,
          maxColor = _props.maxColor,
          _props$parameters = _props.parameters,
          parameters = _props$parameters === undefined ? {} : _props$parameters;
      var _state = this.state,
          model = _state.model,
          cellScale = _state.cellScale,
          maxCount = _state.maxCount;

      uniforms = Object.assign({}, uniforms, { minColor: minColor, maxColor: maxColor, cellScale: cellScale, maxCount: maxCount });
      model.draw({
        uniforms: uniforms,
        parameters: Object.assign({
          depthTest: false,
          depthMask: false
        }, parameters)
      });
    }
  }, {
    key: '_getModel',
    value: function _getModel(gl) {
      return new _luma.Model(gl, Object.assign({}, this.getShaders(), {
        id: this.props.id,
        geometry: new _luma.Geometry({
          drawMode: _luma.GL.TRIANGLE_FAN,
          attributes: {
            vertices: new Float32Array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0])
          }
        }),
        isInstanced: true,
        shaderCache: this.context.shaderCache
      }));
    }
  }, {
    key: 'updateCell',
    value: function updateCell() {
      var _context$viewport = this.context.viewport,
          width = _context$viewport.width,
          height = _context$viewport.height;
      var cellSizePixels = this.props.cellSizePixels;


      var MARGIN = 2;
      var cellScale = new Float32Array([(cellSizePixels - MARGIN) / width * 2, -(cellSizePixels - MARGIN) / height * 2, 1]);
      var numCol = Math.ceil(width / cellSizePixels);
      var numRow = Math.ceil(height / cellSizePixels);

      this.setState({
        cellScale: cellScale,
        numCol: numCol,
        numRow: numRow,
        numInstances: numCol * numRow
      });

      var attributeManager = this.getAttributeManager();
      attributeManager.invalidateAll();
    }
  }, {
    key: 'calculateInstancePositions',
    value: function calculateInstancePositions(attribute, _ref4) {
      var numInstances = _ref4.numInstances;
      var _context$viewport2 = this.context.viewport,
          width = _context$viewport2.width,
          height = _context$viewport2.height;
      var cellSizePixels = this.props.cellSizePixels;
      var numCol = this.state.numCol;
      var value = attribute.value,
          size = attribute.size;


      for (var i = 0; i < numInstances; i++) {
        var x = i % numCol;
        var y = Math.floor(i / numCol);
        value[i * size + 0] = x * cellSizePixels / width * 2 - 1;
        value[i * size + 1] = 1 - y * cellSizePixels / height * 2;
        value[i * size + 2] = 0;
      }
    }
  }, {
    key: 'calculateInstanceColors',
    value: function calculateInstanceColors(attribute) {
      var _props2 = this.props,
          data = _props2.data,
          cellSizePixels = _props2.cellSizePixels,
          getPosition = _props2.getPosition,
          getWeight = _props2.getWeight;
      var _state2 = this.state,
          numCol = _state2.numCol,
          numRow = _state2.numRow,
          numInstances = _state2.numInstances;
      var value = attribute.value,
          size = attribute.size;

      var weights = new Array(numInstances);
      var maxCount = 0;

      weights.fill(0.0);

      // aggregate weights
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = data[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var point = _step.value;

          var pixel = this.project(getPosition(point));
          var colId = Math.floor(pixel[0] / cellSizePixels);
          var rowId = Math.floor(pixel[1] / cellSizePixels);
          if (colId >= 0 && colId < numCol && rowId >= 0 && rowId < numRow) {
            var _i = colId + rowId * numCol;
            weights[_i] += getWeight(point);
            if (weights[_i] > maxCount) {
              maxCount = weights[_i];
            }
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      this.setState({ maxCount: maxCount });

      // Convert weights to colors.
      for (var i = 0; i < numInstances; i++) {
        var color = this._getColor(weights[i], maxCount);
        var index = i * size;
        value[index + 0] = color[0];
        value[index + 1] = color[1];
        value[index + 2] = color[2];
        value[index + 3] = color[3];
      }
    }
  }, {
    key: '_getColor',
    value: function _getColor(weight, maxCount) {
      var color = void 0;
      var _props3 = this.props,
          minColor = _props3.minColor,
          maxColor = _props3.maxColor,
          colorRange = _props3.colorRange;

      if (minColor || maxColor) {
        var step = weight / maxCount;
        // We are supporting optional props as deprecated, set default value if not provided
        color = (0, _mathUtils.lerp)(minColor || [0, 0, 0, 255], maxColor || [0, 255, 0, 255], step);
        return color;
      }
      // if colorDomain not set , use default domain [1, maxCount]
      var colorDomain = this.props.colorDomain || [1, maxCount];
      if (weight < colorDomain[0] || weight > colorDomain[1]) {
        // wight outside the domain, set color alpha to 0.
        return [0, 0, 0, 0];
      }
      color = quantizeScale(colorDomain, colorRange, weight);
      // add alpha to color if not defined in colorRange
      color[3] = Number.isFinite(color[3]) ? color[3] : 255;
      return color;
    }
  }]);

  return ScreenGridLayer;
}(_core.Layer);

exports.default = ScreenGridLayer;


ScreenGridLayer.layerName = 'ScreenGridLayer';
ScreenGridLayer.defaultProps = defaultProps;
//# sourceMappingURL=screen-grid-layer.js.map