/**
 * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
/**
 * @module ui/bindings/addkeyboardhandlingforgrid
 */
/**
 * A helper that adds a keyboard navigation support (arrow up/down/left/right) for grids.
 *
 * @param {Object} options Configuration options.
 * @param {module:utils/keystrokehandler~KeystrokeHandler} options.keystrokeHandler Keystroke handler to register navigation with arrow
 * keys.
 * @param {module:utils/focustracker~FocusTracker} options.focusTracker A focus tracker for grid elements.
 * @param {module:ui/viewcollection~ViewCollection} options.gridItems A collection of grid items.
 * @param {Number|Function} options.numberOfColumns Number of columns in the grid. Can be specified as a function that returns
 * the number (e.g. for responsive grids).
 * @param {String|undefined} options.uiLanguageDirection String of ui language direction.
 */
export default function addKeyboardHandlingForGrid({ keystrokeHandler, focusTracker, gridItems, numberOfColumns, uiLanguageDirection }) {
    const getNumberOfColumns = typeof numberOfColumns === 'number' ? () => numberOfColumns : numberOfColumns;
    keystrokeHandler.set('arrowright', getGridItemFocuser((focusedElementIndex, gridItems) => {
        return uiLanguageDirection === 'rtl' ?
            getLeftElementIndex(focusedElementIndex, gridItems.length) :
            getRightElementIndex(focusedElementIndex, gridItems.length);
    }));
    keystrokeHandler.set('arrowleft', getGridItemFocuser((focusedElementIndex, gridItems) => {
        return uiLanguageDirection === 'rtl' ?
            getRightElementIndex(focusedElementIndex, gridItems.length) :
            getLeftElementIndex(focusedElementIndex, gridItems.length);
    }));
    keystrokeHandler.set('arrowup', getGridItemFocuser((focusedElementIndex, gridItems) => {
        let nextIndex = focusedElementIndex - getNumberOfColumns();
        if (nextIndex < 0) {
            nextIndex = focusedElementIndex + getNumberOfColumns() * Math.floor(gridItems.length / getNumberOfColumns());
            if (nextIndex > gridItems.length - 1) {
                nextIndex -= getNumberOfColumns();
            }
        }
        return nextIndex;
    }));
    keystrokeHandler.set('arrowdown', getGridItemFocuser((focusedElementIndex, gridItems) => {
        let nextIndex = focusedElementIndex + getNumberOfColumns();
        if (nextIndex > gridItems.length - 1) {
            nextIndex = focusedElementIndex % getNumberOfColumns();
        }
        return nextIndex;
    }));
    function getGridItemFocuser(getIndexToFocus) {
        return (evt) => {
            const focusedElement = gridItems.find(item => item.element === focusTracker.focusedElement);
            const focusedElementIndex = gridItems.getIndex(focusedElement);
            const nextIndexToFocus = getIndexToFocus(focusedElementIndex, gridItems);
            gridItems.get(nextIndexToFocus).focus();
            evt.stopPropagation();
            evt.preventDefault();
        };
    }
    // Function returning the next index.
    //
    // before: [ ][x][ ]	after: [ ][ ][x]
    // index = 1            index = 2
    //
    // If current index is last, function returns first index.
    //
    // before: [ ][ ][x]	after: [x][ ][ ]
    // index = 2            index = 0
    //
    // @param {number} [elementIndex] Number of current index.
    // @param {number} [collectionLength] A count of collection items.
    function getRightElementIndex(elementIndex, collectionLength) {
        if (elementIndex === collectionLength - 1) {
            return 0;
        }
        else {
            return elementIndex + 1;
        }
    }
    // Function returning the previous index.
    //
    // before: [ ][x][ ]	after: [x][ ][ ]
    // index = 1            index = 0
    //
    // If current index is first, function returns last index.
    //
    // before: [x][ ][ ]	after: [ ][ ][x]
    // index = 0            index = 2
    //
    // @param {number} [elementIndex] Number of current index.
    // @param {number} [collectionLength] A count of collection items.
    function getLeftElementIndex(elementIndex, collectionLength) {
        if (elementIndex === 0) {
            return collectionLength - 1;
        }
        else {
            return elementIndex - 1;
        }
    }
}
