"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.yfmTableCellView = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const _core_1 = require("../../../../../../core/index.js");
const utils_1 = require("../../../../../../pm/utils.js");
const ReactRenderer_1 = require("../../../../../behavior/ReactRenderer/index.js");
const lodash_1 = require("../../../../../../lodash.js");
const ErrorBoundary_1 = require("../../../../../../react-utils/ErrorBoundary.js");
const table_utils_1 = require("../../../../../../table-utils/index.js");
const table_desc_1 = require("../../../../../../table-utils/table-desc.js");
const const_1 = require("../../../const.js");
const actions_1 = require("../actions.js");
const clear_cells_1 = require("../commands/clear-cells.js");
const insert_empty_column_1 = require("../commands/insert-empty-column.js");
const insert_empty_row_1 = require("../commands/insert-empty-row.js");
const remove_column_range_1 = require("../commands/remove-column-range.js");
const remove_row_range_1 = require("../commands/remove-row-range.js");
const FloatingMenuControl_1 = require("../components/FloatingMenuControl/index.js");
const const_2 = require("../const.js");
const dnd_1 = require("../dnd/dnd.js");
const dnd_plugin_1 = require("../plugins/dnd-plugin.js");
const utils_2 = require("../utils.js");
const dropCursorParams = {
    color: 'var(--g-color-line-brand)',
    width: 2,
};
const yfmTableCellView = (opts) => (node, view, getPos, decorations) => {
    return new YfmTableCellView(node, view, getPos, decorations, opts);
};
exports.yfmTableCellView = yfmTableCellView;
class YfmTableCellView {
    dom;
    contentDOM;
    _node;
    _view;
    _getPos;
    _renderer;
    _logger;
    _dndEnabled;
    _decoRowUniqKey = null;
    _decoColumnUniqKey = null;
    _cellInfo;
    _dndHandler;
    constructor(node, view, getPos, decorations, opts) {
        this._node = node;
        this._view = view;
        this._getPos = getPos;
        this._logger = (0, _core_1.getLoggerFromState)(view.state).nested({
            node: 'yfm-table',
        });
        this._dndEnabled = opts.dndEnabled;
        this.dom = document.createElement('td');
        this._updateDom();
        this.contentDOM = this.dom;
        this._cellInfo = null;
        this._dndHandler = null;
        this._renderer = (0, ReactRenderer_1.getReactRendererFromState)(view.state).createItem('yfm-table-cell-view', () => {
            if (!this._cellInfo)
                return null;
            const { showRowControl, showColumnControl, rowRange, columnRange } = this._cellInfo;
            return ((0, jsx_runtime_1.jsxs)(ErrorBoundary_1.ErrorLoggerBoundary, { children: [showRowControl && ((0, jsx_runtime_1.jsx)(FloatingMenuControl_1.FloatingMenuControl, { type: "row", acnhorElement: this.dom, dndHandler: this._dndHandler?.row, multiple: rowRange.rowsCount > 1, onMenuOpenToggle: this._onRowControlOpenToggle, onClearCellsClick: this._onRowClearCellsClick, onInsertBeforeClick: this._onRowInsertBeforeClick, onInsertAfterClick: this._onRowInsertAfterClick, onRemoveRangeClick: this._onRowRemoveRangeClick, onRemoveTableClick: this._onRemoveTableClick })), showColumnControl && ((0, jsx_runtime_1.jsx)(FloatingMenuControl_1.FloatingMenuControl, { type: "column", acnhorElement: this.dom, dndHandler: this._dndHandler?.column, multiple: columnRange.columnsCount > 1, onMenuOpenToggle: this._onColumnControlOpenToggle, onClearCellsClick: this._onColumnClearCellsClick, onInsertBeforeClick: this._onColumnInsertBeforeClick, onInsertAfterClick: this._onColumnInsertAfterClick, onRemoveRangeClick: this._onColumnRemoveRangeClick, onRemoveTableClick: this._onRemoveTableClick }))] }));
        });
        this.update(node, decorations);
    }
    update(node, decorations) {
        {
            const prev = this._node;
            this._node = node;
            this._updateDom(prev);
        }
        const cellInfo = this._getCellInfo();
        if (cellInfo && (cellInfo.cell.row === 0 || cellInfo.cell.column === 0)) {
            const info = (this._cellInfo = {
                rowIndex: cellInfo.cell.row,
                columnIndex: cellInfo.cell.column,
                showRowControl: false,
                showColumnControl: false,
                rowRange: cellInfo.tableDesc.base.getRowRangeByRowIdx(cellInfo.cell.row),
                columnRange: cellInfo.tableDesc.base.getColumnRangeByColumnIdx(cellInfo.cell.column),
            });
            for (const deco of decorations) {
                const type = deco.spec[const_2.YfmTableDecorationTypeKey];
                info.showRowControl ||= type === const_2.YfmTableDecorationType.ShowRowControl;
                info.showRowControl ||= type === const_2.YfmTableDecorationType.OpenRowMenu;
                info.showColumnControl ||= type === const_2.YfmTableDecorationType.ShowColumnControl;
                info.showColumnControl ||= type === const_2.YfmTableDecorationType.OpenColumnMenu;
            }
            if (this._dndEnabled && !this._dndHandler)
                this._dndHandler = new dnd_1.YfmTableDnDHandler(this._view, {
                    cellNode: node,
                    cellGetPos: this._getPos,
                    logger: this._logger,
                    dropCursor: dropCursorParams,
                });
            this._dndHandler?.update(node);
        }
        else {
            this._cellInfo = null;
            this._dndHandler?.destroy();
            this._dndHandler = null;
        }
        this._renderer.rerender();
        return true;
    }
    destroy() {
        this._dndHandler?.destroy();
        this._dndHandler = null;
        this._renderer.remove();
        this._onRowControlOpenToggle(false);
        this._onColumnControlOpenToggle(false);
    }
    _updateDom(prev) {
        if (prev?.attrs[const_1.YfmTableAttr.CellAlign]) {
            this.dom.classList.remove(prev.attrs[const_1.YfmTableAttr.CellAlign]);
        }
        if (this._node.attrs[const_1.YfmTableAttr.Colspan])
            this.dom.setAttribute('colspan', this._node.attrs[const_1.YfmTableAttr.Colspan]);
        else
            this.dom.removeAttribute('colspan');
        if (this._node.attrs[const_1.YfmTableAttr.Rowspan])
            this.dom.setAttribute('rowspan', this._node.attrs[const_1.YfmTableAttr.Rowspan]);
        else
            this.dom.removeAttribute('rowspan');
        if (this._node.attrs[const_1.YfmTableAttr.CellAlign]) {
            this.dom.classList.add(this._node.attrs[const_1.YfmTableAttr.CellAlign]);
            this.dom.setAttribute(const_1.YfmTableAttr.CellAlign, this._node.attrs[const_1.YfmTableAttr.Rowspan]);
        }
        else {
            this.dom.removeAttribute(const_1.YfmTableAttr.CellAlign);
        }
    }
    _onRowControlOpenToggle = (open) => {
        if (open === false) {
            if (this._decoRowUniqKey) {
                this._view.dispatch((0, dnd_plugin_1.deactivateRow)(this._view.state.tr, this._decoRowUniqKey));
                this._decoRowUniqKey = null;
            }
            return;
        }
        this._logger.event({ event: 'open-row-menu' });
        const info = this._getCellInfo();
        if (!info)
            return;
        this._decoRowUniqKey = Date.now();
        const rowRange = info.tableDesc.base.getRowRangeByRowIdx(info.cell.row);
        const tr = (0, dnd_plugin_1.activateRows)(this._view.state.tr, {
            controlCell: { from: info.pos, to: info.pos + this._node.nodeSize },
            cells: (0, utils_2.getSelectedCellsForRows)(info.tableDesc, rowRange),
            uniqKey: this._decoRowUniqKey,
        });
        this._view.dispatch(tr);
    };
    _onColumnControlOpenToggle = (open) => {
        if (open === false) {
            if (this._decoColumnUniqKey) {
                this._view.dispatch((0, dnd_plugin_1.deactivateColumn)(this._view.state.tr, this._decoColumnUniqKey));
                this._decoColumnUniqKey = null;
            }
            return;
        }
        this._logger.event({ event: 'open-column-menu' });
        const info = this._getCellInfo();
        if (!info)
            return;
        this._decoColumnUniqKey = Date.now();
        const columnRange = info.tableDesc.base.getColumnRangeByColumnIdx(info.cell.column);
        const tr = (0, dnd_plugin_1.activateColumns)(this._view.state.tr, {
            controlCell: { from: info.pos, to: info.pos + this._node.nodeSize },
            cells: (0, utils_2.getSelectedCellsForColumns)(info.tableDesc, columnRange),
            uniqKey: this._decoColumnUniqKey,
        });
        this._view.dispatch(tr);
    };
    _onRowClearCellsClick = () => {
        this._logger.event({ event: 'row-clear-cells', source: 'row-menu' });
        const info = this._getCellInfo();
        if (info) {
            const rowRange = info.tableDesc.base.getRowRangeByRowIdx(info.cell.row);
            (0, clear_cells_1.clearCells)({
                tablePos: info.table.pos,
                rows: (0, lodash_1.range)(rowRange.startIdx, rowRange.endIdx + 1),
            })(this._view.state, this._view.dispatch);
        }
        this._view.focus();
    };
    _onColumnClearCellsClick = () => {
        this._logger.event({ event: 'column-clear-cells', source: 'column-menu' });
        const info = this._getCellInfo();
        if (info) {
            const colRange = info.tableDesc.base.getColumnRangeByColumnIdx(info.cell.column);
            (0, clear_cells_1.clearCells)({
                tablePos: info.table.pos,
                cols: (0, lodash_1.range)(colRange.startIdx, colRange.endIdx + 1),
            })(this._view.state, this._view.dispatch);
        }
        this._view.focus();
    };
    _onRowInsertBeforeClick = () => {
        this._logger.event({ event: 'row-insert-before', source: 'row-menu' });
        const info = this._getCellInfo();
        if (info) {
            const rowRange = info.tableDesc.base.getRowRangeByRowIdx(info.cell.row);
            this._insertRow(info.tableDesc, rowRange.startIdx);
        }
        this._view.focus();
    };
    _onRowInsertAfterClick = () => {
        this._logger.event({ event: 'row-insert-after', source: 'column-menu' });
        const info = this._getCellInfo();
        if (info) {
            const rowRange = info.tableDesc.base.getRowRangeByRowIdx(info.cell.row);
            this._insertRow(info.tableDesc, rowRange.endIdx + 1);
        }
        this._view.focus();
    };
    _insertRow(tableDesc, rowIndex) {
        (0, insert_empty_row_1.insertEmptyRow)({ tablePos: tableDesc.pos, rowIndex })(this._view.state, this._view.dispatch, this._view);
    }
    _onColumnInsertBeforeClick = () => {
        this._logger.event({ event: 'column-insert-before', source: 'column-menu' });
        const info = this._getCellInfo();
        if (info) {
            const colRange = info.tableDesc.base.getColumnRangeByColumnIdx(info.cell.column);
            this._insertColumn(info.tableDesc, colRange.startIdx);
        }
        this._view.focus();
    };
    _onColumnInsertAfterClick = () => {
        this._logger.event({ event: 'column-insert-after', source: 'column-menu' });
        const info = this._getCellInfo();
        if (info) {
            const colRange = info.tableDesc.base.getColumnRangeByColumnIdx(info.cell.column);
            this._insertColumn(info.tableDesc, colRange.endIdx + 1);
        }
        this._view.focus();
    };
    _insertColumn(tableDesc, colIndex) {
        (0, insert_empty_column_1.insertEmptyColumn)({ tablePos: tableDesc.pos, colIndex })(this._view.state, this._view.dispatch, this._view);
    }
    _onRowRemoveRangeClick = () => {
        this._logger.event({ event: 'row-remove', source: 'row-menu' });
        const info = this._getCellInfo();
        if (info) {
            const rangeIdx = info.tableDesc.base.getRowRangeIdxByRowIdx(info.cell.row);
            (0, remove_row_range_1.removeRowRange)({ tablePos: info.tableDesc.pos, rangeIdx })(this._view.state, this._view.dispatch, this._view);
        }
        this._view.focus();
    };
    _onColumnRemoveRangeClick = () => {
        this._logger.event({ event: 'column-remove', source: 'column-menu' });
        const info = this._getCellInfo();
        if (info) {
            const rangeIdx = info.tableDesc.base.getColumnRangeIdxByColumnIdx(info.cell.column);
            (0, remove_column_range_1.removeColumnRange)({ tablePos: info.tableDesc.pos, rangeIdx })(this._view.state, this._view.dispatch, this._view);
        }
        this._view.focus();
    };
    _onRemoveTableClick = () => {
        this._logger.event({ event: 'table-remove' });
        const info = this._getCellInfo();
        if (info) {
            (0, actions_1.removeYfmTable)(this._view.state, this._view.dispatch, this._view, {
                tablePos: info.table.pos,
                tableNode: info.table.node,
            });
        }
        this._view.focus();
    };
    _getCellInfo() {
        const table = this._getParentTable();
        const tableDesc = table ? table_desc_1.TableDesc.create(table.node)?.bind(table.pos) : undefined;
        const cellInfo = tableDesc?.base.getCellInfo(this._node);
        return cellInfo
            ? { pos: this._getPos(), table: table, tableDesc: tableDesc, cell: cellInfo }
            : undefined;
    }
    _getParentTable = () => {
        const pos = this._getPos();
        return pos !== undefined
            ? (0, utils_1.findParentNodeClosestToPos)(this._view.state.doc.resolve(pos), table_utils_1.isTableNode)
            : undefined;
    };
}
//# sourceMappingURL=yfm-table-cell-view.js.map
