"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const index_esm$1 = require("../../../min-dash/dist/index.esm.js");
const index_esm$2 = require("../../../min-dom/dist/index.esm.js");
const Collections = require("../util/Collections.js");
const Elements = require("../util/Elements.js");
const LayoutUtil = require("../layout/LayoutUtil.js");
const index_esm = require("../../../tiny-svg/dist/index.esm.js");
function d(t, e) {
  return Math.round(t * e) / e;
}
function v(t) {
  return index_esm$1.isNumber(t) ? t + "px" : t;
}
function U(t) {
  for (; t.parent; )
    t = t.parent;
  return t;
}
function q(t) {
  t = index_esm$1.assign({}, { width: "100%", height: "100%" }, t);
  const e = t.container || document.body, i = document.createElement("div");
  return i.setAttribute("class", "djs-container"), index_esm$2.assignStyle(i, {
    position: "relative",
    overflow: "hidden",
    width: v(t.width),
    height: v(t.height)
  }), e.appendChild(i), i;
}
function m(t, e, i) {
  const o = index_esm.create("g");
  index_esm.classes(o).add(e);
  const n = i !== void 0 ? i : t.childNodes.length - 1;
  return t.insertBefore(o, t.childNodes[n] || null), o;
}
const X = "base", R = 0, Z = 1, H = {
  shape: ["x", "y", "width", "height"],
  connection: ["waypoints"]
};
function r(t, e, i, o) {
  this._eventBus = e, this._elementRegistry = o, this._graphicsFactory = i, this._rootsIdx = 0, this._layers = {}, this._planes = [], this._rootElement = null, this._init(t || {});
}
r.$inject = [
  "config.canvas",
  "eventBus",
  "graphicsFactory",
  "elementRegistry"
];
r.prototype._init = function(t) {
  const e = this._eventBus, i = this._container = q(t), o = this._svg = index_esm.create("svg");
  index_esm.attr(o, { width: "100%", height: "100%" }), index_esm.append(i, o);
  const n = this._viewport = m(o, "viewport");
  t.deferUpdate !== false && (this._viewboxChanged = index_esm$1.debounce(index_esm$1.bind(this._viewboxChanged, this), 300)), e.on("diagram.init", function() {
    e.fire("canvas.init", {
      svg: o,
      viewport: n
    });
  }, this), e.on([
    "shape.added",
    "connection.added",
    "shape.removed",
    "connection.removed",
    "elements.changed",
    "root.set"
  ], function() {
    delete this._cachedViewbox;
  }, this), e.on("diagram.destroy", 500, this._destroy, this), e.on("diagram.clear", 500, this._clear, this);
};
r.prototype._destroy = function(t) {
  this._eventBus.fire("canvas.destroy", {
    svg: this._svg,
    viewport: this._viewport
  });
  const e = this._container.parentNode;
  e && e.removeChild(this._container), delete this._svg, delete this._container, delete this._layers, delete this._planes, delete this._rootElement, delete this._viewport;
};
r.prototype._clear = function() {
  this._elementRegistry.getAll().forEach((e) => {
    const i = Elements.getType(e);
    i === "root" ? this.removeRootElement(e) : this._removeElement(e, i);
  }), this._planes = [], this._rootElement = null, delete this._cachedViewbox;
};
r.prototype.getDefaultLayer = function() {
  return this.getLayer(X, R);
};
r.prototype.getLayer = function(t, e) {
  if (!t)
    throw new Error("must specify a name");
  let i = this._layers[t];
  if (i || (i = this._layers[t] = this._createLayer(t, e)), typeof e < "u" && i.index !== e)
    throw new Error("layer <" + t + "> already created at index <" + e + ">");
  return i.group;
};
r.prototype._getChildIndex = function(t) {
  return index_esm$1.reduce(this._layers, function(e, i) {
    return i.visible && t >= i.index && e++, e;
  }, 0);
};
r.prototype._createLayer = function(t, e) {
  typeof e > "u" && (e = Z);
  const i = this._getChildIndex(e);
  return {
    group: m(this._viewport, "layer-" + t, i),
    index: e,
    visible: true
  };
};
r.prototype.showLayer = function(t) {
  if (!t)
    throw new Error("must specify a name");
  const e = this._layers[t];
  if (!e)
    throw new Error("layer <" + t + "> does not exist");
  const i = this._viewport, o = e.group, n = e.index;
  if (e.visible)
    return o;
  const a = this._getChildIndex(n);
  return i.insertBefore(o, i.childNodes[a] || null), e.visible = true, o;
};
r.prototype.hideLayer = function(t) {
  if (!t)
    throw new Error("must specify a name");
  const e = this._layers[t];
  if (!e)
    throw new Error("layer <" + t + "> does not exist");
  const i = e.group;
  return e.visible && (index_esm.remove(i), e.visible = false), i;
};
r.prototype._removeLayer = function(t) {
  const e = this._layers[t];
  e && (delete this._layers[t], index_esm.remove(e.group));
};
r.prototype.getActiveLayer = function() {
  const t = this._findPlaneForRoot(this.getRootElement());
  return t ? t.layer : null;
};
r.prototype.findRoot = function(t) {
  return typeof t == "string" && (t = this._elementRegistry.get(t)), t ? (this._findPlaneForRoot(
    U(t)
  ) || {}).rootElement : void 0;
};
r.prototype.getRootElements = function() {
  return this._planes.map(function(t) {
    return t.rootElement;
  });
};
r.prototype._findPlaneForRoot = function(t) {
  return index_esm$1.find(this._planes, function(e) {
    return e.rootElement === t;
  });
};
r.prototype.getContainer = function() {
  return this._container;
};
r.prototype._updateMarker = function(t, e, i) {
  let o;
  t.id || (t = this._elementRegistry.get(t)), o = this._elementRegistry._elements[t.id], o && (index_esm$1.forEach([o.gfx, o.secondaryGfx], function(n) {
    n && (i ? index_esm.classes(n).add(e) : index_esm.classes(n).remove(e));
  }), this._eventBus.fire("element.marker.update", { element: t, gfx: o.gfx, marker: e, add: !!i }));
};
r.prototype.addMarker = function(t, e) {
  this._updateMarker(t, e, true);
};
r.prototype.removeMarker = function(t, e) {
  this._updateMarker(t, e, false);
};
r.prototype.hasMarker = function(t, e) {
  t.id || (t = this._elementRegistry.get(t));
  const i = this.getGraphics(t);
  return index_esm.classes(i).has(e);
};
r.prototype.toggleMarker = function(t, e) {
  this.hasMarker(t, e) ? this.removeMarker(t, e) : this.addMarker(t, e);
};
r.prototype.getRootElement = function() {
  const t = this._rootElement;
  return t || this._planes.length ? t : this.setRootElement(this.addRootElement(null));
};
r.prototype.addRootElement = function(t) {
  const e = this._rootsIdx++;
  t || (t = {
    id: "__implicitroot_" + e,
    children: [],
    isImplicit: true
  });
  const i = t.layer = "root-" + e;
  this._ensureValid("root", t);
  const o = this.getLayer(i, R);
  return this.hideLayer(i), this._addRoot(t, o), this._planes.push({
    rootElement: t,
    layer: o
  }), t;
};
r.prototype.removeRootElement = function(t) {
  if (typeof t == "string" && (t = this._elementRegistry.get(t)), !!this._findPlaneForRoot(t))
    return this._removeRoot(t), this._removeLayer(t.layer), this._planes = this._planes.filter(function(i) {
      return i.rootElement !== t;
    }), this._rootElement === t && (this._rootElement = null), t;
};
r.prototype.setRootElement = function(t, e) {
  if (index_esm$1.isDefined(e))
    throw new Error("override not supported");
  if (t === this._rootElement)
    return;
  let i;
  if (!t)
    throw new Error("rootElement required");
  return i = this._findPlaneForRoot(t), i || (t = this.addRootElement(t)), this._setRoot(t), t;
};
r.prototype._removeRoot = function(t) {
  const e = this._elementRegistry, i = this._eventBus;
  i.fire("root.remove", { element: t }), i.fire("root.removed", { element: t }), e.remove(t);
};
r.prototype._addRoot = function(t, e) {
  const i = this._elementRegistry, o = this._eventBus;
  o.fire("root.add", { element: t }), i.add(t, e), o.fire("root.added", { element: t, gfx: e });
};
r.prototype._setRoot = function(t, e) {
  const i = this._rootElement;
  i && (this._elementRegistry.updateGraphics(i, null, true), this.hideLayer(i.layer)), t && (e || (e = this._findPlaneForRoot(t).layer), this._elementRegistry.updateGraphics(t, this._svg, true), this.showLayer(t.layer)), this._rootElement = t, this._eventBus.fire("root.set", { element: t });
};
r.prototype._ensureValid = function(t, e) {
  if (!e.id)
    throw new Error("element must have an id");
  if (this._elementRegistry.get(e.id))
    throw new Error("element <" + e.id + "> already exists");
  const i = H[t];
  if (!index_esm$1.every(i, function(n) {
    return typeof e[n] < "u";
  }))
    throw new Error(
      "must supply { " + i.join(", ") + " } with " + t
    );
};
r.prototype._setParent = function(t, e, i) {
  Collections.add(e.children, t, i), t.parent = e;
};
r.prototype._addElement = function(t, e, i, o) {
  i = i || this.getRootElement();
  const n = this._eventBus, a = this._graphicsFactory;
  this._ensureValid(t, e), n.fire(t + ".add", { element: e, parent: i }), this._setParent(e, i, o);
  const s = a.create(t, e, o);
  return this._elementRegistry.add(e, s), a.update(t, e, s), n.fire(t + ".added", { element: e, gfx: s }), e;
};
r.prototype.addShape = function(t, e, i) {
  return this._addElement("shape", t, e, i);
};
r.prototype.addConnection = function(t, e, i) {
  return this._addElement("connection", t, e, i);
};
r.prototype._removeElement = function(t, e) {
  const i = this._elementRegistry, o = this._graphicsFactory, n = this._eventBus;
  if (t = i.get(t.id || t), !!t)
    return n.fire(e + ".remove", { element: t }), o.remove(t), Collections.remove(t.parent && t.parent.children, t), t.parent = null, n.fire(e + ".removed", { element: t }), i.remove(t), t;
};
r.prototype.removeShape = function(t) {
  return this._removeElement(t, "shape");
};
r.prototype.removeConnection = function(t) {
  return this._removeElement(t, "connection");
};
r.prototype.getGraphics = function(t, e) {
  return this._elementRegistry.getGraphics(t, e);
};
r.prototype._changeViewbox = function(t) {
  this._eventBus.fire("canvas.viewbox.changing"), t.apply(this), this._cachedViewbox = null, this._viewboxChanged();
};
r.prototype._viewboxChanged = function() {
  this._eventBus.fire("canvas.viewbox.changed", { viewbox: this.viewbox() });
};
r.prototype.viewbox = function(t) {
  if (t === void 0 && this._cachedViewbox)
    return this._cachedViewbox;
  const e = this._viewport, i = this.getSize();
  let o, n, a, s, h, c, f;
  if (t)
    this._changeViewbox(function() {
      h = Math.min(i.width / t.width, i.height / t.height);
      const u = this._svg.createSVGMatrix().scale(h).translate(-t.x, -t.y);
      index_esm.transform(e, u);
    });
  else
    return a = this._rootElement ? this.getActiveLayer() : null, o = a && a.getBBox() || {}, s = index_esm.transform(e), n = s ? s.matrix : index_esm.createMatrix(), h = d(n.a, 1e3), c = d(-n.e || 0, 1e3), f = d(-n.f || 0, 1e3), t = this._cachedViewbox = {
      x: c ? c / h : 0,
      y: f ? f / h : 0,
      width: i.width / h,
      height: i.height / h,
      scale: h,
      inner: {
        width: o.width || 0,
        height: o.height || 0,
        x: o.x || 0,
        y: o.y || 0
      },
      outer: i
    }, t;
  return t;
};
r.prototype.scroll = function(t) {
  const e = this._viewport;
  let i = e.getCTM();
  return t && this._changeViewbox(function() {
    t = index_esm$1.assign({ dx: 0, dy: 0 }, t || {}), i = this._svg.createSVGMatrix().translate(t.dx, t.dy).multiply(i), b(e, i);
  }), { x: i.e, y: i.f };
};
r.prototype.scrollToElement = function(t, e) {
  let i = 100;
  typeof t == "string" && (t = this._elementRegistry.get(t));
  const o = this.findRoot(t);
  o !== this.getRootElement() && this.setRootElement(o), e || (e = {}), typeof e == "number" && (i = e), e = {
    top: e.top || i,
    right: e.right || i,
    bottom: e.bottom || i,
    left: e.left || i
  };
  const n = Elements.getBBox(t), a = LayoutUtil.asTRBL(n), s = this.viewbox(), h = this.zoom();
  let c, f;
  s.y += e.top / h, s.x += e.left / h, s.width -= (e.right + e.left) / h, s.height -= (e.bottom + e.top) / h;
  const u = LayoutUtil.asTRBL(s);
  if (!(n.width < s.width && n.height < s.height))
    c = n.x - s.x, f = n.y - s.y;
  else {
    const E = Math.max(0, a.right - u.right), B = Math.min(0, a.left - u.left), M = Math.max(0, a.bottom - u.bottom), L = Math.min(0, a.top - u.top);
    c = E || B, f = M || L;
  }
  this.scroll({ dx: -c * h, dy: -f * h });
};
r.prototype.zoom = function(t, e) {
  if (!t)
    return this.viewbox(t).scale;
  if (t === "fit-viewport")
    return this._fitViewport(e);
  let i, o;
  return this._changeViewbox(function() {
    typeof e != "object" && (i = this.viewbox().outer, e = {
      x: i.width / 2,
      y: i.height / 2
    }), o = this._setZoom(t, e);
  }), d(o.a, 1e3);
};
function b(t, e) {
  const i = "matrix(" + e.a + "," + e.b + "," + e.c + "," + e.d + "," + e.e + "," + e.f + ")";
  t.setAttribute("transform", i);
}
r.prototype._fitViewport = function(t) {
  const e = this.viewbox(), i = e.outer, o = e.inner;
  let n, a;
  return o.x >= 0 && o.y >= 0 && o.x + o.width <= i.width && o.y + o.height <= i.height && !t ? a = {
    x: 0,
    y: 0,
    width: Math.max(o.width + o.x, i.width),
    height: Math.max(o.height + o.y, i.height)
  } : (n = Math.min(1, i.width / o.width, i.height / o.height), a = {
    x: o.x + (t ? o.width / 2 - i.width / n / 2 : 0),
    y: o.y + (t ? o.height / 2 - i.height / n / 2 : 0),
    width: i.width / n,
    height: i.height / n
  }), this.viewbox(a), this.viewbox(false).scale;
};
r.prototype._setZoom = function(t, e) {
  const i = this._svg, o = this._viewport, n = i.createSVGMatrix(), a = i.createSVGPoint();
  let s, h, c, f, u;
  c = o.getCTM();
  const y = c.a;
  return e ? (s = index_esm$1.assign(a, e), h = s.matrixTransform(c.inverse()), f = n.translate(h.x, h.y).scale(1 / y * t).translate(-h.x, -h.y), u = c.multiply(f)) : u = n.scale(t), b(this._viewport, u), u;
};
r.prototype.getSize = function() {
  return {
    width: this._container.clientWidth,
    height: this._container.clientHeight
  };
};
r.prototype.getAbsoluteBBox = function(t) {
  const e = this.viewbox();
  let i;
  t.waypoints ? i = this.getGraphics(t).getBBox() : i = t;
  const o = i.x * e.scale - e.x * e.scale, n = i.y * e.scale - e.y * e.scale, a = i.width * e.scale, s = i.height * e.scale;
  return {
    x: o,
    y: n,
    width: a,
    height: s
  };
};
r.prototype.resized = function() {
  delete this._cachedViewbox, this._eventBus.fire("canvas.resized");
};
exports.default = r;
