"use strict";

var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");

var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");

require("core-js/modules/es.function.name");

require("core-js/modules/es.object.to-string");

require("core-js/modules/es.regexp.to-string");

_Object$defineProperty(exports, "__esModule", {
  value: true
});

exports.default = void 0;

var _getIterator2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/get-iterator"));

var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));

var _getIteratorMethod2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/get-iterator-method"));

var _symbol = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/symbol"));

var _from = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/from"));

var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice"));

var _extends2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/extends"));

var _find = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find"));

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray"));

var _react = _interopRequireWildcard(require("react"));

var _reactIntl = require("react-intl");

var _reactMapboxGl = _interopRequireDefault(require("react-mapbox-gl"));

var _mapboxGl = _interopRequireDefault(require("mapbox-gl"));

var _helpers = require("../utils/helpers");

var _styles = require("@material-ui/core/styles");

var _ObservationLayer = _interopRequireDefault(require("./ObservationLayer"));

var _Popup = _interopRequireDefault(require("./Popup"));

function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof _symbol.default === "undefined" || (0, _getIteratorMethod2.default)(o) == null) { if ((0, _isArray.default)(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = (0, _getIterator2.default)(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }

function _unsupportedIterableToArray(o, minLen) { var _context; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = (0, _slice.default)(_context = Object.prototype.toString.call(o)).call(_context, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return (0, _from.default)(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

var useStyles = (0, _styles.makeStyles)({
  container: {
    flex: 1
  },
  '@global': {
    // The "Improve Map" link does not work when Mapeo Desktop is used offline,
    // and since the data the user is looking at is mainly data that is not in
    // OpenStreetMap, this link does not make much sense to the user.
    '.mapbox-improve-map': {
      display: 'none'
    }
  }
});
var fitBoundsOptions = {
  duration: 0,
  padding: 10
};

var noop = function noop() {};

var MapViewContent = function MapViewContent(_ref, ref) {
  var observations = _ref.observations,
      mapboxAccessToken = _ref.mapboxAccessToken,
      getPreset = _ref.getPreset,
      getMedia = _ref.getMedia,
      onClick = _ref.onClick,
      _ref$initialMapPositi = _ref.initialMapPosition,
      initialMapPosition = _ref$initialMapPositi === void 0 ? {} : _ref$initialMapPositi,
      _ref$onMapMove = _ref.onMapMove,
      onMapMove = _ref$onMapMove === void 0 ? noop : _ref$onMapMove,
      _ref$mapStyle = _ref.mapStyle,
      mapStyle = _ref$mapStyle === void 0 ? 'mapbox://styles/mapbox/outdoors-v10' : _ref$mapStyle,
      _ref$print = _ref.print,
      print = _ref$print === void 0 ? false : _ref$print;
  var map = (0, _react.useRef)();
  var classes = useStyles();
  var intl = (0, _reactIntl.useIntl)();

  var _useState = (0, _react.useState)(null),
      _useState2 = (0, _slicedToArray2.default)(_useState, 2),
      hovered = _useState2[0],
      setHovered = _useState2[1];

  var _useState3 = (0, _react.useState)(false),
      _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
      styleLoaded = _useState4[0],
      setStyleLoaded = _useState4[1];

  (0, _react.useImperativeHandle)(ref, function () {
    return {
      fitBounds: function fitBounds() {
        if (!map.current) return;

        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        map.current.fitBounds.apply(map.current, args);
      },
      flyTo: function flyTo() {
        if (!map.current) return;

        for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
          args[_key2] = arguments[_key2];
        }

        map.current.flyTo.apply(map.current, args);
      }
    };
  }); // We don't want to change the map viewport if the observations array changes,
  // which it will do if the filter changes. We only set the bounds for the very
  // initial render, and only if initialMapPosition zoom and center are not set.

  var initialBounds = (0, _react.useMemo)(function () {
    return initialMapPosition.center == null && initialMapPosition.zoom == null ? getBounds(observations) : undefined;
  }, // eslint-disable-next-line react-hooks/exhaustive-deps
  []);
  (0, _react.useEffect)(function () {
    if (!map.current || !observations || !observations.length || map.current.__hasMoved || initialMapPosition.center != null && initialMapPosition.zoom != null) return;
    map.current.__hasMoved = true;
    var bounds = getBounds(observations);
    map.current.flyTo({
      center: [bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2, bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2],
      zoom: 9,
      bearing: 0,
      pitch: 0
    });
  }, [initialMapPosition.center, initialMapPosition.zoom, observations, styleLoaded]); // We don't allow the map to be a controlled component - position can only be
  // set when the map is initially mounted and after that state is internal

  var position = (0, _react.useMemo)(function () {
    var center = initialMapPosition.center,
        zoom = initialMapPosition.zoom,
        bearing = initialMapPosition.bearing,
        pitch = initialMapPosition.pitch;
    var bounds = getBounds(observations); // initialMapPosition overrides default behaviour of fitting the map to the
    // bounds of the observations, but if any properties of initialMapPosition are
    // we set some default values

    return {
      center: center || [bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2, bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2],
      zoom: zoom ? [zoom] : [9],
      bearing: bearing ? [bearing] : [0],
      pitch: pitch ? [pitch] : [0]
    }; // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  var Mapbox = (0, _react.useMemo)(function () {
    return (0, _reactMapboxGl.default)({
      accessToken: mapboxAccessToken,
      dragRotate: false,
      pitchWithRotate: false,
      attributionControl: false,
      logoPosition: 'bottom-right',
      scrollZoom: !print,
      injectCSS: false
    });
  }, [mapboxAccessToken, print]);
  var handleStyleLoad = (0, _react.useCallback)(function (mapInstance) {
    mapInstance.addControl(new _mapboxGl.default.NavigationControl({}));
    mapInstance.addControl(new _mapboxGl.default.ScaleControl({}));
    mapInstance.addControl(new _mapboxGl.default.AttributionControl({
      compact: true
    }));
    map.current = mapInstance;
    setStyleLoaded(true);
  }, []);
  var handleMouseMove = (0, _react.useCallback)(function (e) {
    if (e.features.length === 0) return setHovered(null);
    var obs = (0, _find.default)(observations).call(observations, function (obs) {
      return obs.id === e.features[0].properties.id;
    });
    setHovered(obs);
  }, [observations]);
  var handleMouseLeave = (0, _react.useCallback)(function (e) {
    setHovered(null);
  }, []);
  var handleMapMove = (0, _react.useCallback)(function (map, e) {
    onMapMove({
      center: map.getCenter().toArray(),
      zoom: map.getZoom(),
      bearing: map.getBearing(),
      pitch: map.getPitch()
    });
  }, [onMapMove]);

  function getLastImageUrl(observation
  /*: Observation*/
  )
  /*: string | void*/
  {
    var lastImageAttachment = (0, _helpers.getLastImage)(observation);
    if (!lastImageAttachment) return;
    var media = getMedia(lastImageAttachment, {
      width: _Popup.default.imageSize,
      height: _Popup.default.imageSize
    });
    if (media) return media.src;
  }

  function getName(observation
  /*: Observation*/
  )
  /*: string*/
  {
    var preset = getPreset(observation);
    return preset && preset.name || 'Observation';
  }

  return /*#__PURE__*/_react.default.createElement(Mapbox, (0, _extends2.default)({
    style: mapStyle,
    className: classes.container,
    fitBounds: initialBounds,
    fitBoundsOptions: fitBoundsOptions,
    onStyleLoad: handleStyleLoad,
    onMove: handleMapMove
  }, position), /*#__PURE__*/_react.default.createElement(_ObservationLayer.default, {
    observations: observations,
    onClick: onClick,
    onMouseLeave: handleMouseLeave,
    onMouseMove: handleMouseMove,
    print: print
  }), hovered && /*#__PURE__*/_react.default.createElement(_Popup.default, {
    imageUrl: getLastImageUrl(hovered),
    title: getName(hovered),
    subtitle: intl.formatTime(hovered.created_at, {
      year: 'numeric',
      month: 'long',
      day: '2-digit'
    }),
    coordinates: // $FlowFixMe - these are always non-nullish when on a map
    [hovered.lon, hovered.lat]
  }));
};

var _default = /*#__PURE__*/_react.default.forwardRef(MapViewContent);

exports.default = _default;

function getBounds(observations
/*: Observation[]*/
)
/*: [[number, number], [number, number]]*/
{
  var extent = [[-180, -85], [180, 85]];

  var _iterator = _createForOfIteratorHelper(observations),
      _step;

  try {
    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      var _step$value = _step.value,
          lat = _step$value.lat,
          lon = _step$value.lon;
      if (lon == null || lat == null) continue;
      if (extent[0][0] < lon) extent[0][0] = lon;
      if (extent[0][1] < lat) extent[0][1] = lat;
      if (extent[1][0] > lon) extent[1][0] = lon;
      if (extent[1][1] > lat) extent[1][1] = lat;
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }

  return extent;
}
//# sourceMappingURL=MapViewContent.js.map