"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const index_esm = require("../../../../min-dash/dist/index.esm.js");
const index_esm$1 = require("../../../../min-dom/dist/index.esm.js");
const Elements = require("../../util/Elements.js");
const IdGenerator = require("../../util/IdGenerator.js");
var ids = new IdGenerator.default("ov");
var LOW_PRIORITY = 500;
function Overlays(config, eventBus, canvas, elementRegistry) {
  this._eventBus = eventBus;
  this._canvas = canvas;
  this._elementRegistry = elementRegistry;
  this._ids = ids;
  this._overlayDefaults = index_esm.assign({
    // no show constraints
    show: null,
    // always scale
    scale: true
  }, config && config.defaults);
  this._overlays = {};
  this._overlayContainers = [];
  this._overlayRoot = createRoot(canvas.getContainer());
  this._init();
}
Overlays.$inject = [
  "config.overlays",
  "eventBus",
  "canvas",
  "elementRegistry"
];
Overlays.prototype.get = function(search) {
  if (index_esm.isString(search)) {
    search = { id: search };
  }
  if (index_esm.isString(search.element)) {
    search.element = this._elementRegistry.get(search.element);
  }
  if (search.element) {
    var container = this._getOverlayContainer(search.element, true);
    if (container) {
      return search.type ? index_esm.filter(container.overlays, index_esm.matchPattern({ type: search.type })) : container.overlays.slice();
    } else {
      return [];
    }
  } else if (search.type) {
    return index_esm.filter(this._overlays, index_esm.matchPattern({ type: search.type }));
  } else {
    return search.id ? this._overlays[search.id] : null;
  }
};
Overlays.prototype.add = function(element, type, overlay) {
  if (index_esm.isObject(type)) {
    overlay = type;
    type = null;
  }
  if (!element.id) {
    element = this._elementRegistry.get(element);
  }
  if (!overlay.position) {
    throw new Error("must specifiy overlay position");
  }
  if (!overlay.html) {
    throw new Error("must specifiy overlay html");
  }
  if (!element) {
    throw new Error("invalid element specified");
  }
  var id = this._ids.next();
  overlay = index_esm.assign({}, this._overlayDefaults, overlay, {
    id,
    type,
    element,
    html: overlay.html
  });
  this._addOverlay(overlay);
  return id;
};
Overlays.prototype.remove = function(filter) {
  var overlays = this.get(filter) || [];
  if (!index_esm.isArray(overlays)) {
    overlays = [overlays];
  }
  var self = this;
  index_esm.forEach(overlays, function(overlay) {
    var container = self._getOverlayContainer(overlay.element, true);
    if (overlay) {
      index_esm$1.remove(overlay.html);
      index_esm$1.remove(overlay.htmlContainer);
      delete overlay.htmlContainer;
      delete overlay.element;
      delete self._overlays[overlay.id];
    }
    if (container) {
      var idx = container.overlays.indexOf(overlay);
      if (idx !== -1) {
        container.overlays.splice(idx, 1);
      }
    }
  });
};
Overlays.prototype.show = function() {
  setVisible(this._overlayRoot);
};
Overlays.prototype.hide = function() {
  setVisible(this._overlayRoot, false);
};
Overlays.prototype.clear = function() {
  this._overlays = {};
  this._overlayContainers = [];
  index_esm$1.clear(this._overlayRoot);
};
Overlays.prototype._updateOverlayContainer = function(container) {
  var element = container.element, html = container.html;
  var x = element.x, y = element.y;
  if (element.waypoints) {
    var bbox = Elements.getBBox(element);
    x = bbox.x;
    y = bbox.y;
  }
  setPosition(html, x, y);
  index_esm$1.attr(container.html, "data-container-id", element.id);
};
Overlays.prototype._updateOverlay = function(overlay) {
  var position = overlay.position, htmlContainer = overlay.htmlContainer, element = overlay.element;
  var left = position.left, top = position.top;
  if (position.right !== void 0) {
    var width;
    if (element.waypoints) {
      width = Elements.getBBox(element).width;
    } else {
      width = element.width;
    }
    left = position.right * -1 + width;
  }
  if (position.bottom !== void 0) {
    var height;
    if (element.waypoints) {
      height = Elements.getBBox(element).height;
    } else {
      height = element.height;
    }
    top = position.bottom * -1 + height;
  }
  setPosition(htmlContainer, left || 0, top || 0);
  this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
};
Overlays.prototype._createOverlayContainer = function(element) {
  var html = index_esm$1.domify('<div class="djs-overlays" />');
  index_esm$1.assignStyle(html, { position: "absolute" });
  this._overlayRoot.appendChild(html);
  var container = {
    html,
    element,
    overlays: []
  };
  this._updateOverlayContainer(container);
  this._overlayContainers.push(container);
  return container;
};
Overlays.prototype._updateRoot = function(viewbox) {
  var scale = viewbox.scale || 1;
  var matrix = "matrix(" + [
    scale,
    0,
    0,
    scale,
    -1 * viewbox.x * scale,
    -1 * viewbox.y * scale
  ].join(",") + ")";
  setTransform(this._overlayRoot, matrix);
};
Overlays.prototype._getOverlayContainer = function(element, raw) {
  var container = index_esm.find(this._overlayContainers, function(c) {
    return c.element === element;
  });
  if (!container && !raw) {
    return this._createOverlayContainer(element);
  }
  return container;
};
Overlays.prototype._addOverlay = function(overlay) {
  var id = overlay.id, element = overlay.element, html = overlay.html, htmlContainer, overlayContainer;
  if (html.get && html.constructor.prototype.jquery) {
    html = html.get(0);
  }
  if (index_esm.isString(html)) {
    html = index_esm$1.domify(html);
  }
  overlayContainer = this._getOverlayContainer(element);
  htmlContainer = index_esm$1.domify('<div class="djs-overlay" data-overlay-id="' + id + '">');
  index_esm$1.assignStyle(htmlContainer, { position: "absolute" });
  htmlContainer.appendChild(html);
  if (overlay.type) {
    index_esm$1.classes(htmlContainer).add("djs-overlay-" + overlay.type);
  }
  var elementRoot = this._canvas.findRoot(element);
  var activeRoot = this._canvas.getRootElement();
  setVisible(htmlContainer, elementRoot === activeRoot);
  overlay.htmlContainer = htmlContainer;
  overlayContainer.overlays.push(overlay);
  overlayContainer.html.appendChild(htmlContainer);
  this._overlays[id] = overlay;
  this._updateOverlay(overlay);
  this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
};
Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
  var show = overlay.show, rootElement = this._canvas.findRoot(overlay.element), minZoom = show && show.minZoom, maxZoom = show && show.maxZoom, htmlContainer = overlay.htmlContainer, activeRootElement = this._canvas.getRootElement(), visible = true;
  if (rootElement !== activeRootElement) {
    visible = false;
  } else if (show) {
    if (index_esm.isDefined(minZoom) && minZoom > viewbox.scale || index_esm.isDefined(maxZoom) && maxZoom < viewbox.scale) {
      visible = false;
    }
  }
  setVisible(htmlContainer, visible);
  this._updateOverlayScale(overlay, viewbox);
};
Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
  var shouldScale = overlay.scale, minScale, maxScale, htmlContainer = overlay.htmlContainer;
  var scale, transform = "";
  if (shouldScale !== true) {
    if (shouldScale === false) {
      minScale = 1;
      maxScale = 1;
    } else {
      minScale = shouldScale.min;
      maxScale = shouldScale.max;
    }
    if (index_esm.isDefined(minScale) && viewbox.scale < minScale) {
      scale = (1 / viewbox.scale || 1) * minScale;
    }
    if (index_esm.isDefined(maxScale) && viewbox.scale > maxScale) {
      scale = (1 / viewbox.scale || 1) * maxScale;
    }
  }
  if (index_esm.isDefined(scale)) {
    transform = "scale(" + scale + "," + scale + ")";
  }
  setTransform(htmlContainer, transform);
};
Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
  var self = this;
  index_esm.forEach(this._overlays, function(overlay) {
    self._updateOverlayVisibilty(overlay, viewbox);
  });
};
Overlays.prototype._init = function() {
  var eventBus = this._eventBus;
  var self = this;
  function updateViewbox(viewbox) {
    self._updateRoot(viewbox);
    self._updateOverlaysVisibilty(viewbox);
    self.show();
  }
  eventBus.on("canvas.viewbox.changing", function(event) {
    self.hide();
  });
  eventBus.on("canvas.viewbox.changed", function(event) {
    updateViewbox(event.viewbox);
  });
  eventBus.on(["shape.remove", "connection.remove"], function(e) {
    var element = e.element;
    var overlays = self.get({ element });
    index_esm.forEach(overlays, function(o) {
      self.remove(o.id);
    });
    var container = self._getOverlayContainer(element);
    if (container) {
      index_esm$1.remove(container.html);
      var i = self._overlayContainers.indexOf(container);
      if (i !== -1) {
        self._overlayContainers.splice(i, 1);
      }
    }
  });
  eventBus.on("element.changed", LOW_PRIORITY, function(e) {
    var element = e.element;
    var container = self._getOverlayContainer(element, true);
    if (container) {
      index_esm.forEach(container.overlays, function(overlay) {
        self._updateOverlay(overlay);
      });
      self._updateOverlayContainer(container);
    }
  });
  eventBus.on("element.marker.update", function(e) {
    var container = self._getOverlayContainer(e.element, true);
    if (container) {
      index_esm$1.classes(container.html)[e.add ? "add" : "remove"](e.marker);
    }
  });
  eventBus.on("root.set", function() {
    self._updateOverlaysVisibilty(self._canvas.viewbox());
  });
  eventBus.on("diagram.clear", this.clear, this);
};
function createRoot(parentNode) {
  var root = index_esm$1.domify(
    '<div class="djs-overlay-container" />'
  );
  index_esm$1.assignStyle(root, {
    position: "absolute",
    width: 0,
    height: 0
  });
  parentNode.insertBefore(root, parentNode.firstChild);
  return root;
}
function setPosition(el, x, y) {
  index_esm$1.assignStyle(el, { left: x + "px", top: y + "px" });
}
function setVisible(el, visible) {
  el.style.display = visible === false ? "none" : "";
}
function setTransform(el, transform) {
  el.style["transform-origin"] = "top left";
  ["", "-ms-", "-webkit-"].forEach(function(prefix) {
    el.style[prefix + "transform"] = transform;
  });
}
exports.default = Overlays;
