import { Hooks } from '../../../core/hooks/index.mjs';
import { hasOwnProperty } from '../../../helpers/object.mjs';
import { isFunction } from '../../../helpers/function.mjs';
/**
 * @class DynamicCellMetaMod
 *
 * The `DynamicCellMetaMod` modifier allows for extending cell meta objects
 * (returned by `getCellMeta()` from `MetaManager`)
 * by user-specific properties.
 *
 * The user-specific properties can be added and changed dynamically,
 * either by Handsontable's hooks (`beforeGetCellMeta` and`afterGetCellMeta`),
 * or by Handsontable's `cells` option.
 *
 * The `getCellMeta()` method is used widely throughout the source code.
 * To boost the method's execution time,
 * the logic is triggered only once per one Handsontable slow render cycle.
 */ export class DynamicCellMetaMod {
    /**
   * Extends the cell meta object by user-specific properties.
   *
   * The cell meta object can be extended dynamically,
   * either by Handsontable's hooks (`beforeGetCellMeta` and`afterGetCellMeta`),
   * or by Handsontable's `cells` option.
   *
   * To boost performance, the extending process is triggered only once per one slow Handsontable render cycle.
   *
   * @param {object} cellMeta The cell meta object.
   */ extendCellMeta(cellMeta) {
        const { row: physicalRow, col: physicalColumn } = cellMeta;
        if (this.metaSyncMemo.get(physicalRow)?.has(physicalColumn)) {
            return;
        }
        const { visualRow, visualCol } = cellMeta;
        const hot = this.metaManager.hot;
        const prop = hot.colToProp(visualCol);
        cellMeta.prop = prop;
        hot.runHooks('beforeGetCellMeta', visualRow, visualCol, cellMeta);
        // extend a `type` value, added or changed in the `beforeGetCellMeta` hook
        const cellType = hasOwnProperty(cellMeta, 'type') ? cellMeta.type : null;
        let cellSettings = isFunction(cellMeta.cells) ? cellMeta.cells(physicalRow, physicalColumn, prop) : null;
        if (cellType) {
            if (cellSettings) {
                cellSettings.type = cellSettings.type ?? cellType;
            } else {
                cellSettings = {
                    type: cellType
                };
            }
        }
        if (cellSettings) {
            this.metaManager.updateCellMeta(physicalRow, physicalColumn, cellSettings);
        }
        hot.runHooks('afterGetCellMeta', visualRow, visualCol, cellMeta);
        if (!this.metaSyncMemo.has(physicalRow)) {
            this.metaSyncMemo.set(physicalRow, new Set());
        }
        this.metaSyncMemo.get(physicalRow).add(physicalColumn);
    }
    constructor(metaManager){
        /**
   * @type {Map}
   */ this.metaSyncMemo = new Map();
        this.metaManager = metaManager;
        metaManager.addLocalHook('afterGetCellMeta', (...args)=>this.extendCellMeta(...args));
        Hooks.getSingleton().add('beforeRender', (forceFullRender)=>{
            if (forceFullRender) {
                this.metaSyncMemo.clear();
            }
        }, this.metaManager.hot);
    }
}
