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; }; }();

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

// 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.

import LayerManager from '../lib/layer-manager';
import EffectManager from '../experimental/lib/effect-manager';
import Effect from '../experimental/lib/effect';
import log from '../utils/log';

import { EventManager } from 'mjolnir.js';
import { GL, AnimationLoop, createGLContext, setParameters } from 'luma.gl';
import { Stats } from 'probe.gl';

import assert from '../utils/assert';
/* global document */

function noop() {}

function getPropTypes(PropTypes) {
  return {
    id: PropTypes.string,
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    layers: PropTypes.array, // Array can contain falsy values
    views: PropTypes.array, // Array can contain falsy values
    viewState: PropTypes.object,
    effects: PropTypes.arrayOf(PropTypes.instanceOf(Effect)),
    layerFilter: PropTypes.func,
    glOptions: PropTypes.object,
    gl: PropTypes.object,
    pickingRadius: PropTypes.number,
    onWebGLInitialized: PropTypes.func,
    onBeforeRender: PropTypes.func,
    onAfterRender: PropTypes.func,
    onLayerClick: PropTypes.func,
    onLayerHover: PropTypes.func,
    useDevicePixels: PropTypes.bool,

    // Debug settings
    debug: PropTypes.bool,
    drawPickingColors: PropTypes.bool
  };
}

var defaultProps = {
  id: 'deckgl-overlay',
  pickingRadius: 0,
  layerFilter: null,
  glOptions: {},
  gl: null,
  layers: [],
  effects: [],
  views: null,

  onWebGLInitialized: noop,
  onBeforeRender: noop,
  onAfterRender: noop,
  onLayerClick: null,
  onLayerHover: null,
  useDevicePixels: true,

  debug: false,
  drawPickingColors: false
};

var Deck = function () {
  function Deck(props) {
    _classCallCheck(this, Deck);

    props = Object.assign({}, defaultProps, props);

    this.state = {};
    this.needsRedraw = true;
    this.layerManager = null;
    this.effectManager = null;
    this.stats = new Stats({ id: 'deck.gl' });

    // Bind methods
    this._onRendererInitialized = this._onRendererInitialized.bind(this);
    this._onRenderFrame = this._onRenderFrame.bind(this);

    this.canvas = this._createCanvas(props);
    this.animationLoop = this._createAnimationLoop(props);

    this.setProps(props);

    this.animationLoop.start();
  }

  _createClass(Deck, [{
    key: 'setProps',
    value: function setProps(props) {
      this.stats.timeStart('deck.setProps');
      props = Object.assign({}, this.props, props);
      this.props = props;

      this._setLayerManagerProps(props);

      // TODO - unify setParameters/setOptions/setProps etc naming.
      var _props = props,
          useDevicePixels = _props.useDevicePixels,
          autoResizeDrawingBuffer = _props.autoResizeDrawingBuffer;

      this.animationLoop.setViewParameters({ useDevicePixels: useDevicePixels, autoResizeDrawingBuffer: autoResizeDrawingBuffer });
      this.stats.timeEnd('deck.setProps');
    }
  }, {
    key: 'finalize',
    value: function finalize() {
      this.animationLoop.stop();
      this.animationLoop = null;

      if (this.layerManager) {
        this.layerManager.finalize();
        this.layerManager = null;
      }
    }

    // Public API

  }, {
    key: 'pickObject',
    value: function pickObject(_ref) {
      var x = _ref.x,
          y = _ref.y,
          _ref$radius = _ref.radius,
          radius = _ref$radius === undefined ? 0 : _ref$radius,
          _ref$layerIds = _ref.layerIds,
          layerIds = _ref$layerIds === undefined ? null : _ref$layerIds;

      this.stats.timeStart('deck.pickObject');
      var selectedInfos = this.layerManager.pickObject({ x: x, y: y, radius: radius, layerIds: layerIds, mode: 'query' });
      this.stats.timeEnd('deck.pickObject');
      return selectedInfos.length ? selectedInfos[0] : null;
    }
  }, {
    key: 'pickObjects',
    value: function pickObjects(_ref2) {
      var x = _ref2.x,
          y = _ref2.y,
          _ref2$width = _ref2.width,
          width = _ref2$width === undefined ? 1 : _ref2$width,
          _ref2$height = _ref2.height,
          height = _ref2$height === undefined ? 1 : _ref2$height,
          _ref2$layerIds = _ref2.layerIds,
          layerIds = _ref2$layerIds === undefined ? null : _ref2$layerIds;

      this.stats.timeStart('deck.pickObjects');
      var infos = this.layerManager.pickObjects({ x: x, y: y, width: width, height: height, layerIds: layerIds });
      this.stats.timeEnd('deck.pickObjects');
      return infos;
    }
  }, {
    key: 'getViewports',
    value: function getViewports() {
      return this.layerManager ? this.layerManager.getViewports() : [];
    }

    // Private Methods

    // canvas, either string, canvas or `null`

  }, {
    key: '_createCanvas',
    value: function _createCanvas(props) {
      var canvas = props.canvas;

      // TODO EventManager should accept element id
      if (typeof canvas === 'string') {
        /* global document */
        canvas = document.getElementById(canvas);
        assert(canvas);
      }

      if (!canvas) {
        var id = props.id,
            width = props.width,
            height = props.height,
            style = props.style;

        canvas = document.createElement('canvas');
        canvas.id = id;
        canvas.width = width;
        canvas.height = height;
        Object.assign(canvas.style, style);

        var parent = props.parent || document.body;
        parent.appendChild(canvas);
      }

      return canvas;
    }
  }, {
    key: '_createAnimationLoop',
    value: function _createAnimationLoop(props) {
      var _this = this;

      var width = props.width,
          height = props.height,
          gl = props.gl,
          glOptions = props.glOptions,
          debug = props.debug,
          useDevicePixels = props.useDevicePixels,
          autoResizeDrawingBuffer = props.autoResizeDrawingBuffer;


      return new AnimationLoop({
        width: width,
        height: height,
        useDevicePixels: useDevicePixels,
        autoResizeDrawingBuffer: autoResizeDrawingBuffer,
        onCreateContext: function onCreateContext(opts) {
          return gl || createGLContext(Object.assign({}, glOptions, { canvas: _this.canvas, debug: debug }));
        },
        onInitialize: this._onRendererInitialized,
        onRender: this._onRenderFrame,
        onBeforeRender: props.onBeforeRender,
        onAfterRender: props.onAfterRender
      });
    }
  }, {
    key: '_setLayerManagerProps',
    value: function _setLayerManagerProps(props) {
      if (!this.layerManager) {
        return;
      }

      var width = props.width,
          height = props.height,
          views = props.views,
          viewState = props.viewState,
          layers = props.layers,
          pickingRadius = props.pickingRadius,
          onLayerClick = props.onLayerClick,
          onLayerHover = props.onLayerHover,
          useDevicePixels = props.useDevicePixels,
          drawPickingColors = props.drawPickingColors,
          layerFilter = props.layerFilter;

      // If more parameters need to be updated on layerManager add them to this method.

      this.layerManager.setParameters({
        width: width,
        height: height,
        views: views,
        viewState: viewState,
        layers: layers,
        useDevicePixels: useDevicePixels,
        drawPickingColors: drawPickingColors,
        layerFilter: layerFilter,
        pickingRadius: pickingRadius,
        onLayerClick: onLayerClick,
        onLayerHover: onLayerHover
      });
    }

    // Callbacks

  }, {
    key: '_onRendererInitialized',
    value: function _onRendererInitialized(_ref3) {
      var gl = _ref3.gl,
          canvas = _ref3.canvas;

      setParameters(gl, {
        blend: true,
        blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA],
        polygonOffsetFill: true,
        depthTest: true,
        depthFunc: GL.LEQUAL
      });

      this.props.onWebGLInitialized(gl);

      // Note: avoid React setState due GL animation loop / setState timing issue
      this.layerManager = new LayerManager(gl, {
        eventManager: new EventManager(canvas),
        stats: this.stats
      });

      this.effectManager = new EffectManager({ gl: gl, layerManager: this.layerManager });

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this.props.effects[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var effect = _step.value;

          this.effectManager.addEffect(effect);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      this.setProps(this.props);
    }
  }, {
    key: '_onRenderFrame',
    value: function _onRenderFrame(_ref4) {
      var gl = _ref4.gl;

      if (this.stats.oneSecondPassed()) {
        var table = this.stats.getStatsTable();
        this.stats.reset();
        log.table(1, table)();
      }

      // Update layers if needed (e.g. some async prop has loaded)
      this.layerManager.updateLayers();

      this.stats.bump('fps');

      var redrawReason = this.layerManager.needsRedraw({ clearRedrawFlags: true });
      if (!redrawReason) {
        return;
      }

      this.stats.bump('render-fps');

      if (this.props.onBeforeRender) {
        this.props.onBeforeRender({ gl: gl }); // TODO - should be called by AnimationLoop
      }
      this.layerManager.drawLayers({
        pass: 'screen',
        redrawReason: redrawReason,
        // Helps debug layer picking, especially in framebuffer powered layers
        drawPickingColors: this.props.drawPickingColors
      });
      if (this.props.onAfterRender) {
        this.props.onAfterRender({ gl: gl }); // TODO - should be called by AnimationLoop
      }
    }
  }]);

  return Deck;
}();

export default Deck;


Deck.displayName = 'Deck';
Deck.getPropTypes = getPropTypes;
Deck.defaultProps = defaultProps;
//# sourceMappingURL=deck.js.map