/* eslint-disable no-continue */ "use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "SelectionScanner", {
    enumerable: true,
    get: function() {
        return SelectionScanner;
    }
});
const _element = require("../../../../helpers/dom/element");
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);
}
var /**
   * Active Selection instance to process.
   *
   * @type {Selection}
   */ _selection = /*#__PURE__*/ new WeakMap(), /**
   * The Walkontable instance that the scans depends on.
   *
   * @type {Walkontable}
   */ _activeOverlaysWot = /*#__PURE__*/ new WeakMap(), /**
   * The method triggers a callback for each rendered cell.
   *
   * @param {function(number, number): void} callback The callback function to trigger.
   */ _scanCellsRange = /*#__PURE__*/ new WeakSet(), /**
   * The method triggers a callback for each rendered cell including headers.
   *
   * @param {function(number, number): void} callback The callback function to trigger.
   */ _scanViewportRange = /*#__PURE__*/ new WeakSet();
class SelectionScanner {
    /**
   * Sets the Walkontable instance that will be taking into account while scanning the table.
   *
   * @param {Walkontable} activeOverlaysWot The Walkontable instance.
   * @returns {SelectionScanner}
   */ setActiveOverlay(activeOverlaysWot) {
        _class_private_field_set(this, _activeOverlaysWot, activeOverlaysWot);
        return this;
    }
    /**
   * Sets the Selection instance to process.
   *
   * @param {Selection} selection The Selection instance.
   * @returns {SelectionScanner}
   */ setActiveSelection(selection) {
        _class_private_field_set(this, _selection, selection);
        return this;
    }
    /**
   * Scans the rendered table with selection and returns elements that intersects
   * with selection coordinates.
   *
   * @returns {HTMLTableElement[]}
   */ scan() {
        const selectionType = _class_private_field_get(this, _selection).settings.selectionType;
        const elements = new Set();
        // TODO(improvement): use heuristics from coords to detect what type of scan
        // the Selection needs instead of using `selectionType` property.
        if (selectionType === 'active-header') {
            this.scanColumnsInHeadersRange((element)=>elements.add(element));
            this.scanRowsInHeadersRange((element)=>elements.add(element));
        } else if (selectionType === 'area') {
            this.scanCellsRange((element)=>elements.add(element));
        } else if (selectionType === 'focus') {
            this.scanColumnsInHeadersRange((element)=>elements.add(element));
            this.scanRowsInHeadersRange((element)=>elements.add(element));
            this.scanCellsRange((element)=>elements.add(element));
        } else if (selectionType === 'fill') {
            this.scanCellsRange((element)=>elements.add(element));
        } else if (selectionType === 'header') {
            this.scanColumnsInHeadersRange((element)=>elements.add(element));
            this.scanRowsInHeadersRange((element)=>elements.add(element));
        } else if (selectionType === 'row') {
            this.scanRowsInHeadersRange((element)=>elements.add(element));
            this.scanRowsInCellsRange((element)=>elements.add(element));
        } else if (selectionType === 'column') {
            this.scanColumnsInHeadersRange((element)=>elements.add(element));
            this.scanColumnsInCellsRange((element)=>elements.add(element));
        }
        return elements;
    }
    /**
   * Scans the table (only rendered headers) and collect all column headers (TH) that match
   * the coordinates passed in the Selection instance.
   *
   * @param {function(HTMLTableElement): void} callback The callback function to trigger.
   */ scanColumnsInHeadersRange(callback) {
        const [topRow, topColumn, bottomRow, bottomColumn] = _class_private_field_get(this, _selection).getCorners();
        const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
        const renderedColumnsCount = wtTable.getRenderedColumnsCount();
        const columnHeadersCount = wtTable.getColumnHeadersCount();
        let cursor = 0;
        for(let column = -wtTable.getRowHeadersCount(); column < renderedColumnsCount; column++){
            const sourceColumn = wtTable.columnFilter.renderedToSource(column);
            if (sourceColumn < topColumn || sourceColumn > bottomColumn) {
                continue;
            }
            for(let headerLevel = -columnHeadersCount; headerLevel < 0; headerLevel++){
                if (headerLevel < topRow || headerLevel > bottomRow) {
                    continue;
                }
                const positiveBasedHeaderLevel = headerLevel + columnHeadersCount;
                let TH = wtTable.getColumnHeader(sourceColumn, positiveBasedHeaderLevel);
                const newSourceCol = _class_private_field_get(this, _activeOverlaysWot).getSetting('onBeforeHighlightingColumnHeader', sourceColumn, positiveBasedHeaderLevel, {
                    selectionType: _class_private_field_get(this, _selection).settings.selectionType,
                    columnCursor: cursor,
                    selectionWidth: bottomColumn - topColumn + 1
                });
                if (newSourceCol === null) {
                    continue;
                }
                if (newSourceCol !== sourceColumn) {
                    TH = wtTable.getColumnHeader(newSourceCol, positiveBasedHeaderLevel);
                }
                callback(TH);
            }
            cursor += 1;
        }
    }
    /**
   * Scans the table (only rendered headers) and collect all row headers (TH) that match
   * the coordinates passed in the Selection instance.
   *
   * @param {function(HTMLTableElement): void} callback The callback function to trigger.
   */ scanRowsInHeadersRange(callback) {
        const [topRow, topColumn, bottomRow, bottomColumn] = _class_private_field_get(this, _selection).getCorners();
        const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
        const renderedRowsCount = wtTable.getRenderedRowsCount();
        const rowHeadersCount = wtTable.getRowHeadersCount();
        let cursor = 0;
        for(let row = -wtTable.getColumnHeadersCount(); row < renderedRowsCount; row++){
            const sourceRow = wtTable.rowFilter.renderedToSource(row);
            if (sourceRow < topRow || sourceRow > bottomRow) {
                continue;
            }
            for(let headerLevel = -rowHeadersCount; headerLevel < 0; headerLevel++){
                if (headerLevel < topColumn || headerLevel > bottomColumn) {
                    continue;
                }
                const positiveBasedHeaderLevel = headerLevel + rowHeadersCount;
                let TH = wtTable.getRowHeader(sourceRow, positiveBasedHeaderLevel);
                const newSourceRow = _class_private_field_get(this, _activeOverlaysWot).getSetting('onBeforeHighlightingRowHeader', sourceRow, positiveBasedHeaderLevel, {
                    selectionType: _class_private_field_get(this, _selection).settings.selectionType,
                    rowCursor: cursor,
                    selectionHeight: bottomRow - topRow + 1
                });
                if (newSourceRow === null) {
                    continue;
                }
                if (newSourceRow !== sourceRow) {
                    TH = wtTable.getRowHeader(newSourceRow, positiveBasedHeaderLevel);
                }
                callback(TH);
            }
            cursor += 1;
        }
    }
    /**
   * Scans the table (only rendered cells) and collect all cells (TR) that match
   * the coordinates passed in the Selection instance.
   *
   * @param {function(HTMLTableElement): void} callback The callback function to trigger.
   */ scanCellsRange(callback) {
        const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
        _class_private_method_get(this, _scanCellsRange, scanCellsRange).call(this, (sourceRow, sourceColumn)=>{
            const cell = wtTable.getCell(_class_private_field_get(this, _activeOverlaysWot).createCellCoords(sourceRow, sourceColumn));
            // support for old API
            const additionalSelectionClass = _class_private_field_get(this, _activeOverlaysWot).getSetting('onAfterDrawSelection', sourceRow, sourceColumn, _class_private_field_get(this, _selection).settings.layerLevel);
            if (typeof additionalSelectionClass === 'string') {
                (0, _element.addClass)(cell, additionalSelectionClass);
            }
            callback(cell);
        });
    }
    /**
   * Scans the table (only rendered cells) and collects all cells (TR) that match the coordinates
   * passed in the Selection instance but only for the X axis (rows).
   *
   * @param {function(HTMLTableElement): void} callback The callback function to trigger.
   */ scanRowsInCellsRange(callback) {
        // eslint-disable-next-line comma-spacing
        const [topRow, , bottomRow] = _class_private_field_get(this, _selection).getCorners();
        const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
        _class_private_method_get(this, _scanViewportRange, scanViewportRange).call(this, (sourceRow, sourceColumn)=>{
            if (sourceRow >= topRow && sourceRow <= bottomRow) {
                const cell = wtTable.getCell(_class_private_field_get(this, _activeOverlaysWot).createCellCoords(sourceRow, sourceColumn));
                callback(cell);
            }
        });
    }
    /**
   * Scans the table (only rendered cells) and collects all cells (TR) that match the coordinates
   * passed in the Selection instance but only for the Y axis (columns).
   *
   * @param {function(HTMLTableElement): void} callback The callback function to trigger.
   */ scanColumnsInCellsRange(callback) {
        const [, topColumn, , bottomColumn] = _class_private_field_get(this, _selection).getCorners();
        const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
        _class_private_method_get(this, _scanViewportRange, scanViewportRange).call(this, (sourceRow, sourceColumn)=>{
            if (sourceColumn >= topColumn && sourceColumn <= bottomColumn) {
                const cell = wtTable.getCell(_class_private_field_get(this, _activeOverlaysWot).createCellCoords(sourceRow, sourceColumn));
                callback(cell);
            }
        });
    }
    constructor(){
        _class_private_method_init(this, _scanCellsRange);
        _class_private_method_init(this, _scanViewportRange);
        _class_private_field_init(this, _selection, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _activeOverlaysWot, {
            writable: true,
            value: void 0
        });
    }
}
function scanCellsRange(callback) {
    let [topRow, startColumn, bottomRow, endColumn] = _class_private_field_get(this, _selection).getCorners();
    if (topRow < 0 && bottomRow < 0 || startColumn < 0 && endColumn < 0) {
        return;
    }
    const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
    const isMultiple = topRow !== bottomRow || startColumn !== endColumn;
    startColumn = Math.max(startColumn, 0);
    endColumn = Math.max(endColumn, 0);
    topRow = Math.max(topRow, 0);
    bottomRow = Math.max(bottomRow, 0);
    if (isMultiple) {
        startColumn = Math.max(startColumn, wtTable.getFirstRenderedColumn());
        endColumn = Math.min(endColumn, wtTable.getLastRenderedColumn());
        topRow = Math.max(topRow, wtTable.getFirstRenderedRow());
        bottomRow = Math.min(bottomRow, wtTable.getLastRenderedRow());
        if (endColumn < startColumn || bottomRow < topRow) {
            return;
        }
    } else {
        const cell = wtTable.getCell(_class_private_field_get(this, _activeOverlaysWot).createCellCoords(topRow, startColumn));
        if (!(0, _element.isHTMLElement)(cell)) {
            return;
        }
    }
    for(let row = topRow; row <= bottomRow; row += 1){
        for(let column = startColumn; column <= endColumn; column += 1){
            callback(row, column);
        }
    }
}
function scanViewportRange(callback) {
    const { wtTable } = _class_private_field_get(this, _activeOverlaysWot);
    const renderedRowsCount = wtTable.getRenderedRowsCount();
    const renderedColumnsCount = wtTable.getRenderedColumnsCount();
    for(let row = 0; row < renderedRowsCount; row += 1){
        const sourceRow = wtTable.rowFilter.renderedToSource(row);
        for(let column = 0; column < renderedColumnsCount; column += 1){
            callback(sourceRow, wtTable.columnFilter.renderedToSource(column));
        }
    }
}
