var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

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

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

import ViewState from './view-state';

import { Vector3 } from 'math.gl';
import assert from '../utils/assert';

var MOVEMENT_SPEED = 1; // 1 meter per keyboard click
var ROTATION_STEP_DEGREES = 2;

/* Helpers */

// Constrain number between bounds
function clamp(x, min, max) {
  return x < min ? min : x > max ? max : x;
}

function ensureFinite(value, fallbackValue) {
  return Number.isFinite(value) ? value : fallbackValue;
}

var FirstPersonState = function (_ViewState) {
  _inherits(FirstPersonState, _ViewState);

  function FirstPersonState(_ref) {
    var width = _ref.width,
        height = _ref.height,
        position = _ref.position,
        bearing = _ref.bearing,
        pitch = _ref.pitch,
        longitude = _ref.longitude,
        latitude = _ref.latitude,
        zoom = _ref.zoom,
        _ref$syncBearing = _ref.syncBearing,
        syncBearing = _ref$syncBearing === undefined ? true : _ref$syncBearing,
        bounds = _ref.bounds,
        startPanEventPosition = _ref.startPanEventPosition,
        startPanPosition = _ref.startPanPosition,
        startRotateCenter = _ref.startRotateCenter,
        startRotateViewport = _ref.startRotateViewport,
        startZoomPos = _ref.startZoomPos,
        startZoom = _ref.startZoom;

    _classCallCheck(this, FirstPersonState);

    var _this = _possibleConstructorReturn(this, (FirstPersonState.__proto__ || Object.getPrototypeOf(FirstPersonState)).call(this, {
      width: width,
      height: height,
      position: position,
      bearing: bearing,
      pitch: pitch,
      longitude: longitude,
      latitude: latitude,
      zoom: zoom
    }));

    _this._interactiveState = {
      startPanEventPosition: startPanEventPosition,
      startPanPosition: startPanPosition,
      startRotateCenter: startRotateCenter,
      startRotateViewport: startRotateViewport,
      startZoomPos: startZoomPos,
      startZoom: startZoom
    };
    return _this;
  }

  /* Public API */

  _createClass(FirstPersonState, [{
    key: 'getInteractiveState',
    value: function getInteractiveState() {
      return this._interactiveState;
    }

    /**
     * Start panning
     * @param {[Number, Number]} pos - position on screen where the pointer grabs
     */

  }, {
    key: 'panStart',
    value: function panStart(_ref2) {
      var pos = _ref2.pos;
      var _viewportProps = this._viewportProps,
          translationX = _viewportProps.translationX,
          translationY = _viewportProps.translationY;


      return this._getUpdatedState({
        startPanPosition: [translationX, translationY],
        startPanEventPosition: pos
      });
    }

    /**
     * Pan
     * @param {[Number, Number]} pos - position on screen where the pointer is
     */

  }, {
    key: 'pan',
    value: function pan(_ref3) {
      var pos = _ref3.pos,
          startPos = _ref3.startPos;

      var startPanEventPosition = this._interactiveState.startPanEventPosition || startPos;
      assert(startPanEventPosition, '`startPanEventPosition` props is required');

      var _ref4 = this._interactiveState.startPanPosition || [],
          _ref5 = _slicedToArray(_ref4, 2),
          translationX = _ref5[0],
          translationY = _ref5[1];

      translationX = ensureFinite(translationX, this._viewportProps.translationX);
      translationY = ensureFinite(translationY, this._viewportProps.translationY);

      var deltaX = pos[0] - startPanEventPosition[0];
      var deltaY = pos[1] - startPanEventPosition[1];

      return this._getUpdatedState({
        translationX: translationX + deltaX,
        translationY: translationY - deltaY
      });
    }

    /**
     * End panning
     * Must call if `panStart()` was called
     */

  }, {
    key: 'panEnd',
    value: function panEnd() {
      return this._getUpdatedState({
        startPanPosition: null,
        startPanPos: null
      });
    }

    /**
     * Start rotating
     * @param {[Number, Number]} pos - position on screen where the pointer grabs
     */

  }, {
    key: 'rotateStart',
    value: function rotateStart(_ref6) {
      var pos = _ref6.pos;

      return this._getUpdatedState({
        startRotateCenter: this._viewportProps.position,
        startRotateViewport: this._viewportProps
      });
    }

    /**
     * Rotate
     * @param {[Number, Number]} pos - position on screen where the pointer is
     */

  }, {
    key: 'rotate',
    value: function rotate(_ref7) {
      var deltaScaleX = _ref7.deltaScaleX,
          deltaScaleY = _ref7.deltaScaleY;
      var _viewportProps2 = this._viewportProps,
          bearing = _viewportProps2.bearing,
          pitch = _viewportProps2.pitch;


      return this._getUpdatedState({
        bearing: bearing + deltaScaleX * 10,
        pitch: pitch - deltaScaleY * 10
      });
    }

    /**
     * End rotating
     * Must call if `rotateStart()` was called
     */

  }, {
    key: 'rotateEnd',
    value: function rotateEnd() {
      return this._getUpdatedState({
        startRotateCenter: null,
        startRotateViewport: null
      });
    }

    /**
     * Start zooming
     * @param {[Number, Number]} pos - position on screen where the pointer grabs
     */

  }, {
    key: 'zoomStart',
    value: function zoomStart(_ref8) {
      var pos = _ref8.pos;

      return this._getUpdatedState({
        startZoomPos: pos,
        startZoom: this._viewportProps.zoom
      });
    }

    /**
     * Zoom
     * @param {[Number, Number]} pos - position on screen where the current center is
     * @param {[Number, Number]} startPos - the center position at
     *   the start of the operation. Must be supplied of `zoomStart()` was not called
     * @param {Number} scale - a number between [0, 1] specifying the accumulated
     *   relative scale.
     */

  }, {
    key: 'zoom',
    value: function zoom(_ref9) {
      var pos = _ref9.pos,
          startPos = _ref9.startPos,
          scale = _ref9.scale;
      var _viewportProps3 = this._viewportProps,
          zoom = _viewportProps3.zoom,
          minZoom = _viewportProps3.minZoom,
          maxZoom = _viewportProps3.maxZoom,
          width = _viewportProps3.width,
          height = _viewportProps3.height,
          translationX = _viewportProps3.translationX,
          translationY = _viewportProps3.translationY;


      var startZoomPos = this._interactiveState.startZoomPos || startPos || pos;

      var newZoom = clamp(zoom * scale, minZoom, maxZoom);
      var deltaX = pos[0] - startZoomPos[0];
      var deltaY = pos[1] - startZoomPos[1];

      // Zoom around the center position
      var cx = startZoomPos[0] - width / 2;
      var cy = height / 2 - startZoomPos[1];
      /* eslint-disable no-unused-vars */
      var newTranslationX = cx - (cx - translationX) * newZoom / zoom + deltaX;
      var newTranslationY = cy - (cy - translationY) * newZoom / zoom - deltaY;
      /* eslint-enable no-unused-vars */

      // return this._getUpdatedState({
      //   position
      //   translationX: newTranslationX,
      //   translationY: newTranslationY
      // });

      // TODO HACK
      return newZoom / zoom < 1 ? this.moveBackward() : this.moveForward();
    }

    /**
     * End zooming
     * Must call if `zoomStart()` was called
     */

  }, {
    key: 'zoomEnd',
    value: function zoomEnd() {
      return this._getUpdatedState({
        startZoomPos: null,
        startZoom: null
      });
    }
  }, {
    key: 'moveLeft',
    value: function moveLeft() {
      var bearing = this._viewportProps.bearing;

      var newBearing = bearing - ROTATION_STEP_DEGREES;
      return this._getUpdatedState({
        bearing: newBearing
      });
    }
  }, {
    key: 'moveRight',
    value: function moveRight() {
      var bearing = this._viewportProps.bearing;

      var newBearing = bearing + ROTATION_STEP_DEGREES;
      return this._getUpdatedState({
        bearing: newBearing
      });
    }
  }, {
    key: 'moveForward',
    value: function moveForward() {
      var position = this._viewportProps.position;

      var direction = this.getDirection();
      var delta = new Vector3(direction).normalize().scale(MOVEMENT_SPEED);
      return this._getUpdatedState({
        position: new Vector3(position).add(delta)
      });
    }
  }, {
    key: 'moveBackward',
    value: function moveBackward() {
      var position = this._viewportProps.position;

      var direction = this.getDirection();
      var delta = new Vector3(direction).normalize().scale(-MOVEMENT_SPEED);
      return this._getUpdatedState({
        position: new Vector3(position).add(delta)
      });
    }
  }, {
    key: 'moveUp',
    value: function moveUp() {
      var position = this._viewportProps.position;

      var delta = [0, 0, 1];
      return this._getUpdatedState({
        position: new Vector3(position).add(delta)
      });
    }
  }, {
    key: 'moveDown',
    value: function moveDown() {
      var position = this._viewportProps.position;

      var delta = position[2] >= 1 ? [0, 0, -1] : [0, 0, 0];
      return this._getUpdatedState({
        position: new Vector3(position).add(delta)
      });
    }
  }, {
    key: 'zoomIn',
    value: function zoomIn() {
      return this._getUpdatedState({
        zoom: this._viewportProps.zoom + 0.2
      });
    }
  }, {
    key: 'zoomOut',
    value: function zoomOut() {
      return this._getUpdatedState({
        zoom: this._viewportProps.zoom - 0.2
      });
    }

    /* Private methods */

  }, {
    key: '_getUpdatedState',
    value: function _getUpdatedState(newProps) {
      // Update _viewportProps
      return new FirstPersonState(Object.assign({}, this._viewportProps, this._interactiveState, newProps));
    }
  }]);

  return FirstPersonState;
}(ViewState);

export default FirstPersonState;
//# sourceMappingURL=first-person-state.js.map