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