"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var resize_hit_zone_overlay_exports = {};
__export(resize_hit_zone_overlay_exports, {
  ResizeHitZoneOverlay: () => ResizeHitZoneOverlay
});
module.exports = __toCommonJS(resize_hit_zone_overlay_exports);
var import_resizer_scss = __toESM(require("../../statics/styles/resizer-scss.js"));
var import_tablemap = require("../tablemap.js");
var import_column_resizing = require("./column-resizing.js");
var import_resize_drag_controller = require("./resize-drag-controller.js");
var import_resizing_plugin_keys = require("./resizing-plugin-keys.js");
var import_row_resizing = require("./row-resizing.js");
var import_table_editing_plugin = require("./table-editing-plugin.js");
const removeResizeHoverClasses = (zone) => {
  zone.classList.remove(import_resizer_scss.default.peerHovered, import_resizer_scss.default.active);
};
const forEachUnblockedRun = (blocked, visitRun) => {
  let runStart = -1;
  for (let index = 0; index <= blocked.length; index++) {
    const isBlocked = index === blocked.length ? true : blocked[index];
    if (isBlocked) {
      if (runStart !== -1) {
        visitRun({
          start: runStart,
          end: index - 1,
          blockedBefore: runStart > 0 && blocked[runStart - 1],
          blockedAfter: index < blocked.length
        });
        runStart = -1;
      }
    } else if (runStart === -1) {
      runStart = index;
    }
  }
};
const getColumnResizeSegments = (geometry, map) => {
  const { totalCols, totalRows, columnLefts, columnWidths, rowTops, rowBottoms, cellSpacing } = geometry;
  const segments = [];
  const blockedRows = new Array(totalRows);
  for (let colIdx = 0; colIdx < totalCols; colIdx++) {
    const isLastCol = colIdx === totalCols - 1;
    for (let rowIdx = 0; rowIdx < totalRows; rowIdx++) {
      blockedRows[rowIdx] = !isLastCol && map.map[rowIdx * totalCols + colIdx] === map.map[rowIdx * totalCols + colIdx + 1];
    }
    forEachUnblockedRun(blockedRows, ({ start, end, blockedBefore, blockedAfter }) => {
      const top = blockedBefore ? rowTops[start] + cellSpacing / 2 : rowTops[start];
      const bottom = blockedAfter ? rowBottoms[end] + cellSpacing / 2 : rowBottoms[end];
      const rightEdgeX = columnLefts[colIdx] + columnWidths[colIdx];
      const center = isLastCol ? rightEdgeX : rightEdgeX + cellSpacing / 2;
      segments.push({ colIdx, top, bottom, center });
    });
  }
  return segments;
};
const getRowResizeSegments = (geometry, map) => {
  const { totalCols, totalRows, columnLefts, columnWidths, rowBottoms, cellSpacing } = geometry;
  const segments = [];
  const blockedCols = new Array(totalCols);
  for (let rowIdx = 0; rowIdx < totalRows; rowIdx++) {
    const isLastRow = rowIdx === totalRows - 1;
    for (let colIdx = 0; colIdx < totalCols; colIdx++) {
      blockedCols[colIdx] = !isLastRow && map.map[rowIdx * totalCols + colIdx] === map.map[(rowIdx + 1) * totalCols + colIdx];
    }
    forEachUnblockedRun(blockedCols, ({ start, end, blockedBefore, blockedAfter }) => {
      const left = blockedBefore ? columnLefts[start] + cellSpacing / 2 : columnLefts[start];
      const right = blockedAfter ? columnLefts[end] + columnWidths[end] + cellSpacing / 2 : columnLefts[end] + columnWidths[end];
      const bottomEdgeY = rowBottoms[rowIdx];
      const center = isLastRow ? bottomEdgeY : bottomEdgeY + cellSpacing / 2;
      segments.push({ rowIdx, left, right, center });
    });
  }
  return segments;
};
const wireBoundaryPeerHover = (zone, { findBoundaryPeers, isAxisHovered, setHoverActive, clearOtherAxisHover }) => {
  zone.addEventListener("pointerenter", () => {
    setHoverActive(true);
    clearOtherAxisHover();
    findBoundaryPeers(zone).forEach((s) => s.classList.add(import_resizer_scss.default.peerHovered));
  });
  zone.addEventListener("pointerleave", () => {
    requestAnimationFrame(() => {
      const peers = findBoundaryPeers(zone);
      if (peers.some((s) => s.matches(":hover"))) {
        return;
      }
      peers.forEach((s) => s.classList.remove(import_resizer_scss.default.peerHovered));
      if (!isAxisHovered()) {
        setHoverActive(false);
      }
    });
  });
};
const markBoundaryActiveUntilPointerRelease = (view, pointerId, zone, findBoundaryPeers, refreshOverlay) => {
  const peers = findBoundaryPeers(zone);
  peers.forEach((peer) => peer.classList.add(import_resizer_scss.default.active));
  (0, import_resize_drag_controller.setResizeTick)(view, refreshOverlay);
  const clearActiveBoundary = () => {
    (0, import_resizing_plugin_keys.clearResizeHoverActive)(view);
    peers.forEach(removeResizeHoverClasses);
    (0, import_resize_drag_controller.clearResizeTick)(view, refreshOverlay);
    document.removeEventListener("pointerup", clear, true);
    document.removeEventListener("pointercancel", clear, true);
  };
  const clear = (event) => {
    if (event.pointerId === pointerId) {
      clearActiveBoundary();
    }
  };
  document.addEventListener("pointerup", clear, true);
  document.addEventListener("pointercancel", clear, true);
  return clearActiveBoundary;
};
const resizeHitZoneArray = (zones, target, createZone, removeZone) => {
  while (zones.length > target) {
    const zone = zones.pop();
    if (zone) {
      removeZone(zone);
      zone.remove();
    }
  }
  while (zones.length < target) {
    zones.push(createZone());
  }
};
class ColumnResizeHitZones {
  constructor({
    editor,
    getPos,
    dom,
    getNode,
    hitZoneSize,
    clearOtherAxisHover,
    refreshOverlay
  }) {
    this.zones = [];
    this.findBoundaryPeers = (zone) => {
      const overlay = zone.parentElement;
      const colIdx = zone.dataset.colIdx;
      if (!overlay || colIdx === void 0) {
        return [zone];
      }
      return Array.from(
        overlay.querySelectorAll(
          `.${import_resizer_scss.default.columnResizeHitZone}[data-col-idx="${colIdx}"]`
        )
      );
    };
    this.isAxisHovered = () => {
      return this.zones.some((zone) => zone.matches(":hover"));
    };
    this.setHoverActive = (active) => {
      (0, import_resizing_plugin_keys.setColumnResizeHoverActive)(this.editor.view, active);
    };
    this.handlePointerDown = (event) => {
      if (event.button !== 0 || (0, import_table_editing_plugin.isSelectingCells)(this.editor.state) || !this.editor.isEditable) {
        return;
      }
      const target = event.currentTarget;
      const colIdx = Number(target.dataset.colIdx);
      if (!Number.isFinite(colIdx)) {
        return;
      }
      const map = import_tablemap.TableMap.get(this.getNode());
      const isLast = colIdx === map.width - 1;
      const tablePosition = this.getPos() + 1;
      this.setHoverActive(false);
      const clearActiveBoundary = markBoundaryActiveUntilPointerRelease(
        this.editor.view,
        event.pointerId,
        target,
        this.findBoundaryPeers,
        this.refreshOverlay
      );
      const startColumnResizeDrag = (0, import_column_resizing.getStartColumnResizeDrag)(this.editor);
      const didStart = startColumnResizeDrag?.(this.editor.view, {
        tablePosition,
        columnInfo: { index: colIdx },
        nextColumnInfo: isLast ? void 0 : { index: colIdx + 1 },
        event
      });
      if (!didStart) {
        clearActiveBoundary();
        return;
      }
    };
    this.editor = editor;
    this.getPos = getPos;
    this.dom = dom;
    this.getNode = getNode;
    this.hitZoneSize = hitZoneSize;
    this.clearOtherAxisHover = clearOtherAxisHover;
    this.refreshOverlay = refreshOverlay;
  }
  sync(geometry, map) {
    const segments = getColumnResizeSegments(geometry, map);
    resizeHitZoneArray(
      this.zones,
      segments.length,
      () => this.createZone(),
      () => this.setHoverActive(false)
    );
    for (let index = 0; index < segments.length; index++) {
      this.positionZone(this.zones[index], segments[index], geometry);
    }
  }
  clearHover() {
    this.zones.forEach(removeResizeHoverClasses);
    this.setHoverActive(false);
  }
  createZone() {
    const zone = document.createElement("div");
    zone.className = import_resizer_scss.default.columnResizeHitZone;
    this.dom.appendChild(zone);
    zone.addEventListener("pointerdown", this.handlePointerDown);
    wireBoundaryPeerHover(zone, {
      findBoundaryPeers: this.findBoundaryPeers,
      isAxisHovered: this.isAxisHovered,
      setHoverActive: this.setHoverActive,
      clearOtherAxisHover: this.clearOtherAxisHover
    });
    return zone;
  }
  positionZone(zone, segment, geometry) {
    const left = Math.min(
      Math.max(segment.center - this.hitZoneSize / 2, 0),
      Math.max(geometry.tableWidth - this.hitZoneSize, 0)
    );
    zone.style.left = `${left}px`;
    zone.style.top = `${segment.top}px`;
    zone.style.width = `${this.hitZoneSize}px`;
    zone.style.height = `${segment.bottom - segment.top}px`;
    zone.dataset.colIdx = String(segment.colIdx);
    zone.dataset.tableEdge = segment.colIdx === geometry.totalCols - 1 ? "right" : "";
  }
}
class RowResizeHitZones {
  constructor({
    editor,
    getPos,
    dom,
    getNode,
    hitZoneSize,
    clearOtherAxisHover,
    refreshOverlay
  }) {
    this.zones = [];
    this.findBoundaryPeers = (zone) => {
      const overlay = zone.parentElement;
      const rowIdx = zone.dataset.rowIdx;
      if (!overlay || rowIdx === void 0) {
        return [zone];
      }
      return Array.from(
        overlay.querySelectorAll(
          `.${import_resizer_scss.default.rowResizeHitZone}[data-row-idx="${rowIdx}"]`
        )
      );
    };
    this.isAxisHovered = () => {
      return this.zones.some((zone) => zone.matches(":hover"));
    };
    this.setHoverActive = (active) => {
      (0, import_resizing_plugin_keys.setRowResizeHoverActive)(this.editor.view, active);
    };
    this.handlePointerDown = (event) => {
      if (event.button !== 0 || (0, import_table_editing_plugin.isSelectingCells)(this.editor.state) || !this.editor.isEditable) {
        return;
      }
      const target = event.currentTarget;
      const rowIdx = Number(target.dataset.rowIdx);
      if (!Number.isFinite(rowIdx)) {
        return;
      }
      const node = this.getNode();
      const tablePosition = this.getPos() + 1;
      let rowPos;
      let nextRowPos;
      let currentRowIndex = 0;
      node.forEach((_node, offset) => {
        if (currentRowIndex === rowIdx) {
          rowPos = tablePosition + offset;
        }
        if (currentRowIndex === rowIdx + 1) {
          nextRowPos = tablePosition + offset;
        }
        currentRowIndex++;
      });
      if (rowPos === void 0) {
        return;
      }
      this.setHoverActive(false);
      const clearActiveBoundary = markBoundaryActiveUntilPointerRelease(
        this.editor.view,
        event.pointerId,
        target,
        this.findBoundaryPeers,
        this.refreshOverlay
      );
      const startRowResizeDrag = (0, import_row_resizing.getStartRowResizeDrag)(this.editor);
      const didStart = startRowResizeDrag?.(this.editor.view, {
        tablePosition,
        rowInfo: { position: rowPos, index: rowIdx },
        nextRowInfo: nextRowPos !== void 0 ? { position: nextRowPos, index: rowIdx + 1 } : void 0,
        event
      });
      if (!didStart) {
        clearActiveBoundary();
        return;
      }
    };
    this.editor = editor;
    this.getPos = getPos;
    this.dom = dom;
    this.getNode = getNode;
    this.hitZoneSize = hitZoneSize;
    this.clearOtherAxisHover = clearOtherAxisHover;
    this.refreshOverlay = refreshOverlay;
  }
  sync(geometry, map) {
    const segments = getRowResizeSegments(geometry, map);
    resizeHitZoneArray(
      this.zones,
      segments.length,
      () => this.createZone(),
      () => this.setHoverActive(false)
    );
    for (let index = 0; index < segments.length; index++) {
      this.positionZone(this.zones[index], segments[index], geometry);
    }
  }
  clearHover() {
    this.zones.forEach(removeResizeHoverClasses);
    this.setHoverActive(false);
  }
  createZone() {
    const zone = document.createElement("div");
    zone.className = import_resizer_scss.default.rowResizeHitZone;
    this.dom.appendChild(zone);
    zone.addEventListener("pointerdown", this.handlePointerDown);
    wireBoundaryPeerHover(zone, {
      findBoundaryPeers: this.findBoundaryPeers,
      isAxisHovered: this.isAxisHovered,
      setHoverActive: this.setHoverActive,
      clearOtherAxisHover: this.clearOtherAxisHover
    });
    return zone;
  }
  positionZone(zone, segment, geometry) {
    const top = Math.min(
      Math.max(segment.center - this.hitZoneSize / 2, 0),
      Math.max(geometry.tableHeight - this.hitZoneSize, 0)
    );
    zone.style.top = `${top}px`;
    zone.style.left = `${segment.left}px`;
    zone.style.width = `${segment.right - segment.left}px`;
    zone.style.height = `${this.hitZoneSize}px`;
    zone.dataset.rowIdx = String(segment.rowIdx);
    zone.dataset.tableEdge = segment.rowIdx === geometry.totalRows - 1 ? "bottom" : "";
  }
}
class ResizeHitZoneOverlay {
  constructor({
    editor,
    node,
    getPos,
    columnHitZoneWidth,
    rowHitZoneHeight,
    viewport,
    table,
    colgroup,
    contentDOM,
    onResizeTick
  }) {
    this.pendingUpdateRaf = 0;
    this.refreshOverlay = () => {
      this.update();
      this.onResizeTick();
    };
    this.editor = editor;
    this.node = node;
    this.table = table;
    this.colgroup = colgroup;
    this.contentDOM = contentDOM;
    this.onResizeTick = onResizeTick;
    this.dom = document.createElement("div");
    this.dom.className = import_resizer_scss.default.resizeOverlay;
    this.dom.setAttribute("contenteditable", "false");
    viewport.appendChild(this.dom);
    this.columnHitZones = new ColumnResizeHitZones({
      editor,
      getPos,
      dom: this.dom,
      getNode: () => this.node,
      hitZoneSize: columnHitZoneWidth,
      clearOtherAxisHover: () => this.rowHitZones.clearHover(),
      refreshOverlay: this.refreshOverlay
    });
    this.rowHitZones = new RowResizeHitZones({
      editor,
      getPos,
      dom: this.dom,
      getNode: () => this.node,
      hitZoneSize: rowHitZoneHeight,
      clearOtherAxisHover: () => this.columnHitZones.clearHover(),
      refreshOverlay: this.refreshOverlay
    });
  }
  setNode(node) {
    this.node = node;
  }
  scheduleUpdate() {
    if (this.pendingUpdateRaf !== 0) {
      return;
    }
    this.pendingUpdateRaf = requestAnimationFrame(() => {
      this.pendingUpdateRaf = 0;
      this.update();
    });
  }
  destroy() {
    if (this.pendingUpdateRaf !== 0) {
      cancelAnimationFrame(this.pendingUpdateRaf);
      this.pendingUpdateRaf = 0;
    }
    (0, import_resize_drag_controller.clearResizeTick)(this.editor.view, this.refreshOverlay);
    (0, import_resizing_plugin_keys.clearResizeHoverActive)(this.editor.view);
  }
  update() {
    if (!this.editor.isEditable) {
      this.hide();
      return;
    }
    const firstRow = this.contentDOM.firstElementChild;
    const rows = this.contentDOM.querySelectorAll(":scope > tr");
    if (!firstRow || !rows.length) {
      this.hide();
      return;
    }
    const map = import_tablemap.TableMap.get(this.node);
    if (map.width === 0 || map.height === 0) {
      this.hide();
      return;
    }
    const cellSpacing = this.node.attrs.tableData?.cellSpacing ?? 0;
    const tableWidth = this.table.offsetWidth;
    const tableHeight = this.table.offsetHeight;
    const geometry = this.getTableGeometry(rows, map, cellSpacing, tableWidth, tableHeight);
    if (!geometry) {
      this.hide();
      return;
    }
    this.dom.style.display = "block";
    this.dom.style.left = `${this.table.offsetLeft}px`;
    this.dom.style.top = `${this.table.offsetTop}px`;
    this.dom.style.width = `${tableWidth}px`;
    this.dom.style.height = `${tableHeight}px`;
    this.columnHitZones.sync(geometry, map);
    this.rowHitZones.sync(geometry, map);
  }
  hide() {
    this.dom.style.display = "none";
    (0, import_resizing_plugin_keys.clearResizeHoverActive)(this.editor.view);
  }
  getTableGeometry(rows, map, cellSpacing, tableWidth, tableHeight) {
    const totalCols = map.width;
    const totalRows = map.height;
    const columnGeometry = this.getColumnGeometry(totalCols);
    if (!columnGeometry) {
      return null;
    }
    const rowTops = new Array(totalRows);
    const rowBottoms = new Array(totalRows);
    for (let r = 0; r < totalRows; r++) {
      const row = rows[r];
      if (!row) {
        return null;
      }
      rowTops[r] = row.offsetTop;
      rowBottoms[r] = row.offsetTop + row.offsetHeight;
    }
    return {
      totalCols,
      totalRows,
      columnLefts: columnGeometry.lefts,
      columnWidths: columnGeometry.widths,
      rowTops,
      rowBottoms,
      tableWidth,
      tableHeight,
      cellSpacing
    };
  }
  getColumnGeometry(totalCols) {
    const cols = Array.from(this.colgroup.children).slice(0, totalCols);
    if (cols.length < totalCols) {
      return null;
    }
    const lefts = new Array(totalCols);
    const widths = new Array(totalCols);
    let left = 0;
    for (let i = 0; i < totalCols; i++) {
      const width = cols[i].offsetWidth;
      if (!Number.isFinite(width)) {
        return null;
      }
      lefts[i] = left;
      widths[i] = width;
      left += width;
    }
    return { lefts, widths };
  }
}
//# sourceMappingURL=resize-hit-zone-overlay.js.map
