"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "SelectionManager", {
    enumerable: true,
    get: function() {
        return SelectionManager;
    }
});
const _element = require("../../../../helpers/dom/element");
const _scanner = require("./scanner");
const _border = /*#__PURE__*/ _interop_require_default(require("./border/border"));
function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_apply_descriptor_get(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _class_apply_descriptor_set(receiver, descriptor, value) {
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
}
function _class_extract_field_descriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _class_private_field_get(receiver, privateMap) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
    return _class_apply_descriptor_get(receiver, descriptor);
}
function _class_private_field_init(obj, privateMap, value) {
    _check_private_redeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _class_private_field_set(receiver, privateMap, value) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
    _class_apply_descriptor_set(receiver, descriptor, value);
    return value;
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
var /**
   * The overlay's Walkontable instance that are currently processed.
   *
   * @type {Walkontable}
   */ _activeOverlaysWot = /*#__PURE__*/ new WeakMap(), /**
   * The Highlight instance that holds Selections instances within it.
   *
   * @type {Highlight|null}
   */ _selections = /*#__PURE__*/ new WeakMap(), /**
   * The SelectionScanner allows to scan and collect the cell and header elements that matches
   * to the coords defined in the selections.
   *
   * @type {SelectionScanner}
   */ _scanner1 = /*#__PURE__*/ new WeakMap(), /**
   * The Map tracks applied CSS classes. It's used to reset the elements state to their initial state.
   *
   * @type {WeakMap}
   */ _appliedClasses = /*#__PURE__*/ new WeakMap(), /**
   * The Map tracks applied "destroy" listeners for Selection instances.
   *
   * @type {WeakMap}
   */ _destroyListeners = /*#__PURE__*/ new WeakMap(), /**
   * The Map holds references to Border classes for Selection instances which requires that when
   * the "border" setting is defined.
   *
   * @type {Map}
   */ _selectionBorders = /*#__PURE__*/ new WeakMap(), /**
   * Resets the elements to their initial state (remove the CSS classes that are added in the
   * previous render cycle).
   */ _resetCells = /*#__PURE__*/ new WeakSet();
class SelectionManager {
    /**
   * Sets the active Walkontable instance.
   *
   * @param {Walkontable} activeWot The overlays or master Walkontable instance.
   * @returns {SelectionManager}
   */ setActiveOverlay(activeWot) {
        _class_private_field_set(this, _activeOverlaysWot, activeWot);
        _class_private_field_get(this, _scanner1).setActiveOverlay(_class_private_field_get(this, _activeOverlaysWot));
        if (!_class_private_field_get(this, _appliedClasses).has(_class_private_field_get(this, _activeOverlaysWot))) {
            _class_private_field_get(this, _appliedClasses).set(_class_private_field_get(this, _activeOverlaysWot), new Set());
        }
        return this;
    }
    /**
   * Gets the Selection instance of the "focus" type.
   *
   * @returns {Selection|null}
   */ getFocusSelection() {
        return _class_private_field_get(this, _selections) !== null ? _class_private_field_get(this, _selections).getFocus() : null;
    }
    /**
   * Gets the Selection instance of the "area" type.
   *
   * @returns {Selection|null}
   */ getAreaSelection() {
        return _class_private_field_get(this, _selections) !== null ? _class_private_field_get(this, _selections).createLayeredArea() : null;
    }
    /**
   * Gets the Border instance associated with Selection instance.
   *
   * @param {Selection} selection The selection instance.
   * @returns {Border|null} Returns the Border instance (new for each overlay Walkontable instance).
   */ getBorderInstance(selection) {
        if (!selection.settings.border) {
            return null;
        }
        if (_class_private_field_get(this, _selectionBorders).has(selection)) {
            const borders = _class_private_field_get(this, _selectionBorders).get(selection);
            if (borders.has(_class_private_field_get(this, _activeOverlaysWot))) {
                return borders.get(_class_private_field_get(this, _activeOverlaysWot));
            }
            const border = new _border.default(_class_private_field_get(this, _activeOverlaysWot), selection.settings);
            borders.set(_class_private_field_get(this, _activeOverlaysWot), border);
            return border;
        }
        const border = new _border.default(_class_private_field_get(this, _activeOverlaysWot), selection.settings);
        _class_private_field_get(this, _selectionBorders).set(selection, new Map([
            [
                _class_private_field_get(this, _activeOverlaysWot),
                border
            ]
        ]));
        return border;
    }
    /**
   * Gets all Border instances associated with Selection instance for all overlays.
   *
   * @param {Selection} selection The selection instance.
   * @returns {Border[]}
   */ getBorderInstances(selection) {
        return Array.from(_class_private_field_get(this, _selectionBorders).get(selection)?.values() ?? []);
    }
    /**
   * Destroys the Border instance associated with Selection instance.
   *
   * @param {Selection} selection The selection instance.
   */ destroyBorders(selection) {
        _class_private_field_get(this, _selectionBorders).get(selection).forEach((border)=>border.destroy());
        _class_private_field_get(this, _selectionBorders).delete(selection);
    }
    /**
   * Refreshes the multiple selector handle styles on all border instances after a theme change.
   */ refreshAllBorderHandleStyles() {
        _class_private_field_get(this, _selectionBorders).forEach((bordersMap)=>{
            bordersMap.forEach((border)=>{
                border.updateMultipleSelectorHandlesStyles?.();
            });
        });
    }
    /**
   * Renders all the selections (add CSS classes to cells and draw borders).
   *
   * @param {boolean} fastDraw Indicates the render cycle type (fast/slow).
   */ render(fastDraw) {
        if (_class_private_field_get(this, _selections) === null) {
            return;
        }
        if (fastDraw) {
            // there was no rerender, so we need to remove classNames by ourselves
            _class_private_method_get(this, _resetCells, resetCells).call(this);
        }
        const selections = Array.from(_class_private_field_get(this, _selections));
        const classNamesMap = new Map();
        const headerAttributesMap = new Map();
        for(let i = 0; i < selections.length; i++){
            const selection = selections[i];
            const { className, headerAttributes, createLayers, selectionType } = selection.settings;
            if (!_class_private_field_get(this, _destroyListeners).has(selection)) {
                _class_private_field_get(this, _destroyListeners).add(selection);
                selection.addLocalHook('destroy', ()=>this.destroyBorders(selection));
            }
            const borderInstance = this.getBorderInstance(selection);
            if (selection.isEmpty()) {
                borderInstance?.disappear();
                continue; // eslint-disable-line no-continue
            }
            if (className) {
                const elements = _class_private_field_get(this, _scanner1).setActiveSelection(selection).scan();
                elements.forEach((element)=>{
                    if (classNamesMap.has(element)) {
                        const classNamesLayers = classNamesMap.get(element);
                        if (classNamesLayers.has(className) && createLayers === true) {
                            classNamesLayers.set(className, classNamesLayers.get(className) + 1);
                        } else {
                            classNamesLayers.set(className, 1);
                        }
                    } else {
                        classNamesMap.set(element, new Map([
                            [
                                className,
                                1
                            ]
                        ]));
                    }
                    if (headerAttributes) {
                        if (!headerAttributesMap.has(element)) {
                            headerAttributesMap.set(element, []);
                        }
                        if (element.nodeName === 'TH') {
                            headerAttributesMap.get(element).push(...headerAttributes);
                        }
                    }
                });
            }
            const corners = selection.getCorners();
            _class_private_field_get(this, _activeOverlaysWot).getSetting('onBeforeDrawBorders', corners, selectionType);
            borderInstance?.appear(corners);
        }
        classNamesMap.forEach((classNamesLayers, element)=>{
            const classNames = Array.from(classNamesLayers).map(([className, occurrenceCount])=>{
                if (occurrenceCount === 1) {
                    return className;
                }
                return [
                    className,
                    ...Array.from({
                        length: occurrenceCount - 1
                    }, (_, i)=>`${className}-${i + 1}`)
                ];
            }).flat();
            classNames.forEach((className)=>_class_private_field_get(this, _appliedClasses).get(_class_private_field_get(this, _activeOverlaysWot)).add(className));
            (0, _element.addClass)(element, classNames);
            if (element.nodeName === 'TD' && Array.isArray(_class_private_field_get(this, _selections).options?.cellAttributes)) {
                (0, _element.setAttribute)(element, _class_private_field_get(this, _selections).options.cellAttributes);
            }
        });
        // Set the attributes for the headers if they're focused.
        Array.from(headerAttributesMap.keys()).forEach((element)=>{
            (0, _element.setAttribute)(element, [
                ...headerAttributesMap.get(element)
            ]);
        });
    }
    constructor(selections){
        _class_private_method_init(this, _resetCells);
        _class_private_field_init(this, _activeOverlaysWot, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _selections, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _scanner1, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _appliedClasses, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _destroyListeners, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _selectionBorders, {
            writable: true,
            value: void 0
        });
        _class_private_field_set(this, _scanner1, new _scanner.SelectionScanner());
        _class_private_field_set(this, _appliedClasses, new WeakMap());
        _class_private_field_set(this, _destroyListeners, new WeakSet());
        _class_private_field_set(this, _selectionBorders, new Map());
        _class_private_field_set(this, _selections, selections);
    }
}
function resetCells() {
    const appliedOverlaysClasses = _class_private_field_get(this, _appliedClasses).get(_class_private_field_get(this, _activeOverlaysWot));
    const classesToRemove = _class_private_field_get(this, _activeOverlaysWot).wtSettings.getSetting('onBeforeRemoveCellClassNames');
    if (Array.isArray(classesToRemove)) {
        for(let i = 0; i < classesToRemove.length; i++){
            appliedOverlaysClasses.add(classesToRemove[i]);
        }
    }
    appliedOverlaysClasses.forEach((className)=>{
        const nodes = _class_private_field_get(this, _activeOverlaysWot).wtTable.TABLE.querySelectorAll(`.${className}`);
        let cellAttributes = [];
        if (Array.isArray(_class_private_field_get(this, _selections).options?.cellAttributes)) {
            cellAttributes = _class_private_field_get(this, _selections).options.cellAttributes.map((el)=>el[0]);
        }
        if (Array.isArray(_class_private_field_get(this, _selections).options?.headerAttributes)) {
            cellAttributes = [
                ...cellAttributes,
                ..._class_private_field_get(this, _selections).options.headerAttributes.map((el)=>el[0])
            ];
        }
        for(let i = 0, len = nodes.length; i < len; i++){
            (0, _element.removeClass)(nodes[i], className);
            (0, _element.removeAttribute)(nodes[i], cellAttributes);
        }
    });
    appliedOverlaysClasses.clear();
}
