"use strict";

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

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _deepEqual = require("../utils/deep-equal");

var _log = _interopRequireDefault(require("../utils/log"));

var _flatten = require("../utils/flatten");

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

var ViewManager = function () {
  function ViewManager(props) {
    (0, _classCallCheck2.default)(this, ViewManager);
    this.width = void 0;
    this.height = void 0;
    this.views = void 0;
    this.viewState = void 0;
    this.controllers = void 0;
    this.timeline = void 0;
    this._viewports = void 0;
    this._viewportMap = void 0;
    this._isUpdating = void 0;
    this._needsRedraw = void 0;
    this._needsUpdate = void 0;
    this._eventManager = void 0;
    this._eventCallbacks = void 0;
    this.views = [];
    this.width = 100;
    this.height = 100;
    this.viewState = {};
    this.controllers = {};
    this.timeline = props.timeline;
    this._viewports = [];
    this._viewportMap = {};
    this._isUpdating = false;
    this._needsRedraw = 'First render';
    this._needsUpdate = 'Initialize';
    this._eventManager = props.eventManager;
    this._eventCallbacks = {
      onViewStateChange: props.onViewStateChange,
      onInteractionStateChange: props.onInteractionStateChange
    };
    Object.seal(this);
    this.setProps(props);
  }

  var _proto = ViewManager.prototype;

  _proto.finalize = function finalize() {
    for (var key in this.controllers) {
      var controller = this.controllers[key];

      if (controller) {
        controller.finalize();
      }
    }

    this.controllers = {};
  };

  _proto.needsRedraw = function needsRedraw() {
    var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
      clearRedrawFlags: false
    };
    var redraw = this._needsRedraw;

    if (opts.clearRedrawFlags) {
      this._needsRedraw = false;
    }

    return redraw;
  };

  _proto.setNeedsUpdate = function setNeedsUpdate(reason) {
    this._needsUpdate = this._needsUpdate || reason;
    this._needsRedraw = this._needsRedraw || reason;
  };

  _proto.updateViewStates = function updateViewStates() {
    for (var _viewId in this.controllers) {
      var controller = this.controllers[_viewId];

      if (controller) {
        controller.updateTransition();
      }
    }
  };

  _proto.getViewports = function getViewports(rect) {
    if (rect) {
      return this._viewports.filter(function (viewport) {
        return viewport.containsPixel(rect);
      });
    }

    return this._viewports;
  };

  _proto.getViews = function getViews() {
    var viewMap = {};
    this.views.forEach(function (view) {
      viewMap[view.id] = view;
    });
    return viewMap;
  };

  _proto.getView = function getView(viewId) {
    return this.views.find(function (view) {
      return view.id === viewId;
    });
  };

  _proto.getViewState = function getViewState(viewOrViewId) {
    var view = typeof viewOrViewId === 'string' ? this.getView(viewOrViewId) : viewOrViewId;
    var viewState = view && this.viewState[view.getViewStateId()] || this.viewState;
    return view ? view.filterViewState(viewState) : viewState;
  };

  _proto.getViewport = function getViewport(viewId) {
    return this._viewportMap[viewId];
  };

  _proto.unproject = function unproject(xyz, opts) {
    var viewports = this.getViewports();
    var pixel = {
      x: xyz[0],
      y: xyz[1]
    };

    for (var i = viewports.length - 1; i >= 0; --i) {
      var viewport = viewports[i];

      if (viewport.containsPixel(pixel)) {
        var p = xyz.slice();
        p[0] -= viewport.x;
        p[1] -= viewport.y;
        return viewport.unproject(p, opts);
      }
    }

    return null;
  };

  _proto.setProps = function setProps(props) {
    if (props.views) {
      this._setViews(props.views);
    }

    if (props.viewState) {
      this._setViewState(props.viewState);
    }

    if ('width' in props || 'height' in props) {
      this._setSize(props.width, props.height);
    }

    if (!this._isUpdating) {
      this._update();
    }
  };

  _proto._update = function _update() {
    this._isUpdating = true;

    if (this._needsUpdate) {
      this._needsUpdate = false;

      this._rebuildViewports();
    }

    if (this._needsUpdate) {
      this._needsUpdate = false;

      this._rebuildViewports();
    }

    this._isUpdating = false;
  };

  _proto._setSize = function _setSize(width, height) {
    if (width !== this.width || height !== this.height) {
      this.width = width;
      this.height = height;
      this.setNeedsUpdate('Size changed');
    }
  };

  _proto._setViews = function _setViews(views) {
    views = (0, _flatten.flatten)(views, Boolean);

    var viewsChanged = this._diffViews(views, this.views);

    if (viewsChanged) {
      this.setNeedsUpdate('views changed');
    }

    this.views = views;
  };

  _proto._setViewState = function _setViewState(viewState) {
    if (viewState) {
      var viewStateChanged = !(0, _deepEqual.deepEqual)(viewState, this.viewState, 3);

      if (viewStateChanged) {
        this.setNeedsUpdate('viewState changed');
      }

      this.viewState = viewState;
    } else {
      _log.default.warn('missing `viewState` or `initialViewState`')();
    }
  };

  _proto._onViewStateChange = function _onViewStateChange(viewId, event) {
    if (this._eventCallbacks.onViewStateChange) {
      this._eventCallbacks.onViewStateChange(_objectSpread(_objectSpread({}, event), {}, {
        viewId: viewId
      }));
    }
  };

  _proto._createController = function _createController(view, props) {
    var _this = this;

    var Controller = props.type;
    var controller = new Controller({
      timeline: this.timeline,
      eventManager: this._eventManager,
      onViewStateChange: this._onViewStateChange.bind(this, props.id),
      onStateChange: this._eventCallbacks.onInteractionStateChange,
      makeViewport: function makeViewport(viewState) {
        var _this$getView;

        return (_this$getView = _this.getView(view.id)) === null || _this$getView === void 0 ? void 0 : _this$getView.makeViewport({
          viewState: viewState,
          width: _this.width,
          height: _this.height
        });
      }
    });
    return controller;
  };

  _proto._updateController = function _updateController(view, viewState, viewport, controller) {
    var controllerProps = view.controller;

    if (controllerProps && viewport) {
      var resolvedProps = _objectSpread(_objectSpread(_objectSpread({}, viewState), controllerProps), {}, {
        id: view.id,
        x: viewport.x,
        y: viewport.y,
        width: viewport.width,
        height: viewport.height
      });

      if (!controller || controller.constructor !== controllerProps.type) {
        controller = this._createController(view, resolvedProps);
      }

      if (controller) {
        controller.setProps(resolvedProps);
      }

      return controller;
    }

    return null;
  };

  _proto._rebuildViewports = function _rebuildViewports() {
    var views = this.views;
    var oldControllers = this.controllers;
    this._viewports = [];
    this.controllers = {};
    var invalidateControllers = false;

    for (var i = views.length; i--;) {
      var view = views[i];
      var viewState = this.getViewState(view);
      var viewport = view.makeViewport({
        viewState: viewState,
        width: this.width,
        height: this.height
      });
      var oldController = oldControllers[view.id];
      var hasController = Boolean(view.controller);

      if (hasController && !oldController) {
        invalidateControllers = true;
      }

      if ((invalidateControllers || !hasController) && oldController) {
        oldController.finalize();
        oldController = null;
      }

      this.controllers[view.id] = this._updateController(view, viewState, viewport, oldController);

      if (viewport) {
        this._viewports.unshift(viewport);
      }
    }

    for (var id in oldControllers) {
      var _oldController = oldControllers[id];

      if (_oldController && !this.controllers[id]) {
        _oldController.finalize();
      }
    }

    this._buildViewportMap();
  };

  _proto._buildViewportMap = function _buildViewportMap() {
    var _this2 = this;

    this._viewportMap = {};

    this._viewports.forEach(function (viewport) {
      if (viewport.id) {
        _this2._viewportMap[viewport.id] = _this2._viewportMap[viewport.id] || viewport;
      }
    });
  };

  _proto._diffViews = function _diffViews(newViews, oldViews) {
    if (newViews.length !== oldViews.length) {
      return true;
    }

    return newViews.some(function (_, i) {
      return !newViews[i].equals(oldViews[i]);
    });
  };

  return ViewManager;
}();

exports.default = ViewManager;
//# sourceMappingURL=view-manager.js.map