"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get SELECTION_TYPES () {
        return SELECTION_TYPES;
    },
    get SELECTION_TYPE_ARRAY () {
        return SELECTION_TYPE_ARRAY;
    },
    get SELECTION_TYPE_EMPTY () {
        return SELECTION_TYPE_EMPTY;
    },
    get SELECTION_TYPE_OBJECT () {
        return SELECTION_TYPE_OBJECT;
    },
    get SELECTION_TYPE_UNRECOGNIZED () {
        return SELECTION_TYPE_UNRECOGNIZED;
    },
    get detectSelectionType () {
        return detectSelectionType;
    },
    get normalizeSelectionFactory () {
        return normalizeSelectionFactory;
    },
    get transformSelectionToColumnDistance () {
        return transformSelectionToColumnDistance;
    },
    get transformSelectionToRowDistance () {
        return transformSelectionToRowDistance;
    }
});
const _src = require("./../3rdparty/walkontable/src");
const _errors = require("../helpers/errors");
const _array = require("./../helpers/array");
const _mixed = require("./../helpers/mixed");
const SELECTION_TYPE_UNRECOGNIZED = 0;
const SELECTION_TYPE_EMPTY = 1;
const SELECTION_TYPE_ARRAY = 2;
const SELECTION_TYPE_OBJECT = 3;
const SELECTION_TYPES = [
    SELECTION_TYPE_OBJECT,
    SELECTION_TYPE_ARRAY
];
const ARRAY_TYPE_PATTERN = [
    [
        'number'
    ],
    [
        'number',
        'string'
    ],
    [
        'number',
        'undefined'
    ],
    [
        'number',
        'string',
        'undefined'
    ]
];
const rootCall = Symbol('root');
const childCall = Symbol('child');
function detectSelectionType(selectionRanges, _callSymbol = rootCall) {
    if (_callSymbol !== rootCall && _callSymbol !== childCall) {
        (0, _errors.throwWithCause)('The second argument is used internally only and cannot be overwritten.');
    }
    const isArray = Array.isArray(selectionRanges);
    const isRootCall = _callSymbol === rootCall;
    let result = SELECTION_TYPE_UNRECOGNIZED;
    if (isArray) {
        const firstItem = selectionRanges[0];
        if (selectionRanges.length === 0) {
            result = SELECTION_TYPE_EMPTY;
        } else if (isRootCall && firstItem instanceof _src.CellRange) {
            result = SELECTION_TYPE_OBJECT;
        } else if (isRootCall && Array.isArray(firstItem)) {
            result = detectSelectionType(firstItem, childCall);
        } else if (selectionRanges.length >= 2 && selectionRanges.length <= 4) {
            const isArrayType = !selectionRanges.some((value, index)=>!ARRAY_TYPE_PATTERN[index].includes(typeof value));
            if (isArrayType) {
                result = SELECTION_TYPE_ARRAY;
            }
        }
    }
    return result;
}
function normalizeSelectionFactory(type, { createCellCoords, createCellRange, keepDirection = false, propToCol } = {}) {
    if (!SELECTION_TYPES.includes(type)) {
        (0, _errors.throwWithCause)('Unsupported selection ranges schema type was provided.');
    }
    return function(selection) {
        const isObjectType = type === SELECTION_TYPE_OBJECT;
        let rowStart = isObjectType ? selection.from.row : selection[0];
        let columnStart = isObjectType ? selection.from.col : selection[1];
        let rowEnd = isObjectType ? selection.to.row : selection[2];
        let columnEnd = isObjectType ? selection.to.col : selection[3];
        if (typeof propToCol === 'function') {
            if (typeof columnStart === 'string') {
                columnStart = propToCol(columnStart);
            }
            if (typeof columnEnd === 'string') {
                columnEnd = propToCol(columnEnd);
            }
        }
        if ((0, _mixed.isUndefined)(rowEnd)) {
            rowEnd = rowStart;
        }
        if ((0, _mixed.isUndefined)(columnEnd)) {
            columnEnd = columnStart;
        }
        if (!keepDirection) {
            const origRowStart = rowStart;
            const origColumnStart = columnStart;
            const origRowEnd = rowEnd;
            const origColumnEnd = columnEnd;
            rowStart = Math.min(origRowStart, origRowEnd);
            columnStart = Math.min(origColumnStart, origColumnEnd);
            rowEnd = Math.max(origRowStart, origRowEnd);
            columnEnd = Math.max(origColumnStart, origColumnEnd);
        }
        const highlight = isObjectType ? selection.highlight.clone() : createCellCoords(rowStart, columnStart);
        const from = createCellCoords(rowStart, columnStart);
        const to = createCellCoords(rowEnd, columnEnd);
        return createCellRange(highlight, from, to);
    };
}
function transformSelectionToColumnDistance(hotInstance) {
    const selectionType = detectSelectionType(hotInstance.getSelected());
    if (selectionType === SELECTION_TYPE_UNRECOGNIZED || selectionType === SELECTION_TYPE_EMPTY) {
        return [];
    }
    const selectionSchemaNormalizer = normalizeSelectionFactory(selectionType, {
        createCellCoords: hotInstance._createCellCoords.bind(hotInstance),
        createCellRange: hotInstance._createCellRange.bind(hotInstance)
    });
    const unorderedIndexes = new Set();
    // Iterate through all ranges and collect all column indexes which are not saved yet.
    (0, _array.arrayEach)(hotInstance.getSelected(), (selection)=>{
        const { from, to } = selectionSchemaNormalizer(selection);
        const columnNonHeaderStart = Math.max(from.col, 0);
        const amount = to.col - columnNonHeaderStart + 1;
        (0, _array.arrayEach)(Array.from(new Array(amount), (_, i)=>columnNonHeaderStart + i), (index)=>{
            if (!unorderedIndexes.has(index)) {
                unorderedIndexes.add(index);
            }
        });
    });
    // Sort indexes in ascending order to easily detecting non-consecutive columns.
    const orderedIndexes = Array.from(unorderedIndexes).sort((a, b)=>a - b);
    const normalizedColumnRanges = (0, _array.arrayReduce)(orderedIndexes, (acc, visualColumnIndex, index, array)=>{
        if (index !== 0 && visualColumnIndex === array[index - 1] + 1) {
            acc[acc.length - 1][1] += 1;
        } else {
            acc.push([
                visualColumnIndex,
                1
            ]);
        }
        return acc;
    }, []);
    return normalizedColumnRanges;
}
function transformSelectionToRowDistance(hotInstance) {
    const selectionType = detectSelectionType(hotInstance.getSelected());
    if (selectionType === SELECTION_TYPE_UNRECOGNIZED || selectionType === SELECTION_TYPE_EMPTY) {
        return [];
    }
    const selectionSchemaNormalizer = normalizeSelectionFactory(selectionType, {
        createCellCoords: hotInstance._createCellCoords.bind(hotInstance),
        createCellRange: hotInstance._createCellRange.bind(hotInstance)
    });
    const unorderedIndexes = new Set();
    // Iterate through all ranges and collect all column indexes which are not saved yet.
    (0, _array.arrayEach)(hotInstance.getSelected(), (selection)=>{
        const { from, to } = selectionSchemaNormalizer(selection);
        const rowNonHeaderStart = Math.max(from.row, 0);
        const amount = to.row - rowNonHeaderStart + 1;
        (0, _array.arrayEach)(Array.from(new Array(amount), (_, i)=>rowNonHeaderStart + i), (index)=>{
            if (!unorderedIndexes.has(index)) {
                unorderedIndexes.add(index);
            }
        });
    });
    // Sort indexes in ascending order to easily detecting non-consecutive columns.
    const orderedIndexes = Array.from(unorderedIndexes).sort((a, b)=>a - b);
    const normalizedRowRanges = (0, _array.arrayReduce)(orderedIndexes, (acc, rowIndex, index, array)=>{
        if (index !== 0 && rowIndex === array[index - 1] + 1) {
            acc[acc.length - 1][1] += 1;
        } else {
            acc.push([
                rowIndex,
                1
            ]);
        }
        return acc;
    }, []);
    return normalizedRowRanges;
}
