"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.yfmTableFocusPlugin = void 0;
exports.hideHoverDecos = hideHoverDecos;
const state_1 = require("../../../../../../pm/state.js");
const utils_1 = require("../../../../../../pm/utils.js");
const view_1 = require("../../../../../../pm/view.js");
const lodash_1 = require("../../../../../../lodash.js");
const table_utils_1 = require("../../../../../../table-utils/index.js");
const table_desc_1 = require("../../../../../../table-utils/table-desc.js");
const YfmTableSpecs_1 = require("../../../YfmTableSpecs/index.js");
const const_1 = require("../const.js");
const yfm_table_cell_view_1 = require("../nodeviews/yfm-table-cell-view.js");
const yfm_table_view_1 = require("../nodeviews/yfm-table-view.js");
const pluginKey = new state_1.PluginKey('TableControlsPlugin');
const FOCUSED_CLASSNAME = 'yfm-table-focused';
function shouldUpdateState(prev, curr) {
    if (prev === null && curr === null)
        return false;
    if (prev === null || curr === null)
        return true;
    if (prev.rowIdx === curr.rowIdx &&
        prev.columnIdx === curr.columnIdx &&
        prev.tablePos === curr.tablePos)
        return false;
    return true;
}
function hideHoverDecos(tr) {
    const meta = { newState: null };
    return tr.setMeta(pluginKey, meta);
}
const yfmTableFocusPlugin = (opts) => {
    return new state_1.Plugin({
        key: pluginKey,
        state: {
            init(_config, state) {
                return updateAfterChanges(state);
            },
            apply: (tr, prev) => {
                if (tr.selectionSet || tr.docChanged) {
                    return updateAfterChanges(tr, prev);
                }
                const meta = tr.getMeta(pluginKey);
                if (meta) {
                    const plState = { ...prev };
                    plState.decorations = plState.decorations.map(tr.mapping, tr.doc);
                    {
                        const decosToRemove = plState.decorations.find(undefined, undefined, (spec) => spec[const_1.YfmTableDecorationTypeKey] === const_1.YfmTableDecorationType.ShowRowControl ||
                            spec[const_1.YfmTableDecorationTypeKey] === const_1.YfmTableDecorationType.ShowColumnControl);
                        plState.decorations = plState.decorations.remove(decosToRemove);
                    }
                    plState.hover = meta.newState;
                    if (plState.hover && plState.activeTablePos === plState.hover.tablePos) {
                        const table = tr.doc.nodeAt(plState.activeTablePos);
                        const tableDesc = table_desc_1.TableDesc.create(table);
                        const rowCell = tableDesc.getRelativePosForCell(plState.hover.rowIdx, 0);
                        const columnCell = tableDesc.getRelativePosForCell(0, plState.hover.columnIdx);
                        if (rowCell.type === 'real') {
                            plState.decorations = plState.decorations.add(tr.doc, [
                                view_1.Decoration.node(plState.activeTablePos + rowCell.from, plState.activeTablePos + rowCell.to, {}, { [const_1.YfmTableDecorationTypeKey]: const_1.YfmTableDecorationType.ShowRowControl }),
                            ]);
                        }
                        if (columnCell.type === 'real') {
                            plState.decorations = plState.decorations.add(tr.doc, [
                                view_1.Decoration.node(plState.activeTablePos + columnCell.from, plState.activeTablePos + columnCell.to, {}, { [const_1.YfmTableDecorationTypeKey]: const_1.YfmTableDecorationType.ShowColumnControl }),
                            ]);
                        }
                    }
                    return plState;
                }
                return { ...prev, decorations: prev.decorations.map(tr.mapping, tr.doc) };
            },
        },
        props: {
            nodeViews: {
                [YfmTableSpecs_1.YfmTableNode.Table]: yfm_table_view_1.yfmTableView,
                [YfmTableSpecs_1.YfmTableNode.Cell]: (0, yfm_table_cell_view_1.yfmTableCellView)(opts),
            },
            decorations(state) {
                return pluginKey.getState(state)?.decorations;
            },
            handleDOMEvents: {
                mousemove: (0, lodash_1.throttle)((view, e) => {
                    let hover = null;
                    if (e.target instanceof Element &&
                        e.target.closest('td') &&
                        e.target.closest(`.${FOCUSED_CLASSNAME}`)) {
                        const $pos = (() => {
                            const td = e.target.closest('td');
                            const domPos = td && view.posAtDOM(td, 0);
                            return domPos === null ? null : view.state.doc.resolve(domPos);
                        })() ??
                            (() => {
                                const pos = view.posAtCoords({ left: e.x, top: e.y });
                                return pos && view.state.doc.resolve(pos.pos);
                            })();
                        const tcell = $pos && (0, utils_1.findParentNodeClosestToPos)($pos, table_utils_1.isTableCellNode);
                        const table = $pos && (0, utils_1.findParentNodeClosestToPos)($pos, table_utils_1.isTableNode);
                        const tableDesc = table && table_desc_1.TableDesc.create(table.node);
                        const cellInfo = tcell && tableDesc?.getCellInfo(tcell.node);
                        if (cellInfo) {
                            hover = {
                                tablePos: table.pos,
                                rowIdx: cellInfo.row,
                                columnIdx: cellInfo.column,
                            };
                            {
                                const rowFirstCell = tableDesc.rowsDesc[hover.rowIdx].cells[0];
                                if (rowFirstCell.type === 'virtual')
                                    hover.rowIdx = rowFirstCell.rowspan[0];
                            }
                            {
                                const colFirstCell = tableDesc.rowsDesc[0].cells[hover.columnIdx];
                                if (colFirstCell.type === 'virtual')
                                    hover.columnIdx = colFirstCell.colspan[1];
                            }
                        }
                    }
                    if (shouldUpdateState(pluginKey.getState(view.state)?.hover || null, hover)) {
                        const meta = { newState: hover };
                        view.dispatch(view.state.tr.setMeta(pluginKey, meta));
                    }
                }, 100),
            },
        },
    });
};
exports.yfmTableFocusPlugin = yfmTableFocusPlugin;
function updateAfterChanges(tr, prev) {
    const table = (0, utils_1.findParentNode)(table_utils_1.isTableNode)(tr.selection) ||
        (0, utils_1.findSelectedNodeOfType)((0, YfmTableSpecs_1.yfmTableType)(tr.doc.type.schema))(tr.selection);
    if (table) {
        const tableFrom = table.pos;
        const tableTo = tableFrom + table.node.nodeSize;
        const decos = prev
            ? prev.decorations
                .map(tr.mapping, tr.doc)
                .find(tableFrom, tableTo, (spec) => spec[const_1.YfmTableDecorationTypeKey] === const_1.YfmTableDecorationType.ShowRowControl ||
                spec[const_1.YfmTableDecorationTypeKey] === const_1.YfmTableDecorationType.ShowColumnControl)
            : [];
        return {
            hover: null,
            activeTablePos: table.pos,
            decorations: view_1.DecorationSet.create(tr.doc, [
                ...decos,
                view_1.Decoration.node(table.pos, table.pos + table.node.nodeSize, { class: FOCUSED_CLASSNAME }, { [const_1.YfmTableDecorationTypeKey]: const_1.YfmTableDecorationType.FocusTable }),
            ]),
        };
    }
    else {
        return {
            hover: null,
            activeTablePos: null,
            decorations: view_1.DecorationSet.empty,
        };
    }
}
//# sourceMappingURL=focus-plugin.js.map
