/* eslint-disable no-continue */ "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 useCarousel () {
        return useCarousel;
    },
    get useCarouselLite () {
        return useCarouselLite;
    }
});
var _lodashthrottle = /*#__PURE__*/ _interop_require_default(require("lodash.throttle"));
var _react = require("react");
var _hooks = require("../../hooks");
var _utils = require("./utils");
function _array_like_to_array(arr, len) {
    if (len == null || len > arr.length) len = arr.length;
    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
    return arr2;
}
function _array_with_holes(arr) {
    if (Array.isArray(arr)) return arr;
}
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _iterable_to_array_limit(arr, i) {
    var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
    if (_i == null) return;
    var _arr = [];
    var _n = true;
    var _d = false;
    var _s, _e;
    try {
        for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
            _arr.push(_s.value);
            if (i && _arr.length === i) break;
        }
    } catch (err) {
        _d = true;
        _e = err;
    } finally{
        try {
            if (!_n && _i["return"] != null) _i["return"]();
        } finally{
            if (_d) throw _e;
        }
    }
    return _arr;
}
function _non_iterable_rest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _sliced_to_array(arr, i) {
    return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
}
function _unsupported_iterable_to_array(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _array_like_to_array(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(n);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
}
var THROTTLE_DEFAULT_MS = 100;
var DEBOUNCE_DEFAULT_MS = 150;
var useCarousel = function useCarousel(param) {
    var index = param.index, axis = param.axis, _param_detectActive = param.detectActive, detectActive = _param_detectActive === void 0 ? false : _param_detectActive, _param_detectThreshold = param.detectThreshold, detectThreshold = _param_detectThreshold === void 0 ? 0.5 : _param_detectThreshold, _param_scrollAlign = param.scrollAlign, scrollAlign = _param_scrollAlign === void 0 ? 'center' : _param_scrollAlign, scaleCallback = param.scaleCallback, scaleResetCallback = param.scaleResetCallback, onIndexChange = param.onIndexChange, onDetectActiveItem = param.onDetectActiveItem, _param_animatedScrollByIndex = param.animatedScrollByIndex, animatedScrollByIndex = _param_animatedScrollByIndex === void 0 ? false : _param_animatedScrollByIndex, _param_throttleMs = param.throttleMs, throttleMs = _param_throttleMs === void 0 ? THROTTLE_DEFAULT_MS : _param_throttleMs, _param_debounceMs = param.debounceMs, debounceMs = _param_debounceMs === void 0 ? DEBOUNCE_DEFAULT_MS : _param_debounceMs;
    var prevIndex = (0, _react.useRef)(null);
    var direction = (0, _react.useRef)(null);
    var offset = (0, _react.useRef)(0);
    var scrollRef = (0, _react.useRef)(null);
    var trackRef = (0, _react.useRef)(null);
    /**
     * Для того, чтобы не спамить изменениями индекса.
     * Задержка дебаунса слегка больше, чем у тротлинга.
     * Таким образом, событие срабатывает при завершении скролла.
     */ var debouncedOnIndexChange = (0, _hooks.useDebouncedFunction)(function(i) {
        return onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(i);
    }, debounceMs);
    /**
     * Вычисление центрального элемента.
     * Подсчет: от 0 до 1, какое количество ширины/высоты
     * каждого элемента находится по центру скролла.
     */ var throttledDetectActiveItem = (0, _react.useMemo)(function() {
        return (0, _lodashthrottle.default)(function() {
            if (!detectActive || scrollRef.current === null || trackRef.current === null) {
                return;
            }
            /**
             * Правая (или нижняя для Оу) граница элемента.
             */ var itemEdge = offset.current;
            /**
             * Смещение (отрицательный или положительный отступ)
             * и размер карусели (для Ox - ширина, для Oy - высота).
             */ var scrollPos = scrollRef.current[axis === 'x' ? 'scrollLeft' : 'scrollTop'];
            var scrollSize = scrollRef.current[axis === 'x' ? 'offsetWidth' : 'offsetHeight'];
            /**
             * Граница скролла (видимой части).
             * Смещение + размер.
             */ var scrollEdge = scrollPos + scrollSize;
            /**
             * Элементы перед, после и в видимой части.
             * перед [ ВИДИМЫЕ ] после
             */ var prevItems = [];
            var nextItems = [];
            var count = 0;
            var items = (0, _utils.getCarouselItems)(trackRef.current);
            /**
             * Проходим по всему списку, суммируя ширины элементов,
             * пока не найдем один элемент, чей центр будет в центре карусели.
             */ for(var itemIndex = 0; itemIndex < items.length; itemIndex++){
                var _prevIndex_current;
                var item = items.item(itemIndex);
                if (item === null) {
                    continue;
                }
                /**
                 * Для Ox - ширина, для Oy - высота.
                 */ var itemSize = item[axis === 'x' ? 'offsetWidth' : 'offsetHeight'];
                /**
                 * Все элементы правее вьюпорта выпадают из процедуры.
                 * Сравниваем по предыдущему элементу.
                 * [ ... ] ...|n| <- Левый край элемента за пределами начала видимой части
                 */ if (itemEdge > scrollEdge) {
                    if (scaleCallback && scaleResetCallback) {
                        nextItems.push(item);
                    }
                    continue;
                }
                itemEdge += itemSize;
                /**
                 * Все элементы левее вьюпорта выпадают из процедуры.
                 * Сравниваем по текущему элементу.
                 * Правый край элемента за пределами начала видимой части -> |p|... [ ... ]
                 */ if (scrollPos > itemEdge) {
                    if (scaleCallback && scaleResetCallback) {
                        prevItems.push(item);
                    }
                    continue;
                }
                var itemSlot = (0, _utils.getItemSlot)(itemIndex, itemEdge, itemSize, scrollPos, scrollSize, scrollAlign, (_prevIndex_current = prevIndex.current) !== null && _prevIndex_current !== void 0 ? _prevIndex_current : 0, offset.current);
                if (itemSlot !== null) {
                    if (detectThreshold && Math.abs(itemSlot) <= detectThreshold) {
                        onDetectActiveItem === null || onDetectActiveItem === void 0 ? void 0 : onDetectActiveItem(itemIndex);
                        debouncedOnIndexChange === null || debouncedOnIndexChange === void 0 ? void 0 : debouncedOnIndexChange(itemIndex);
                    }
                    if (scaleCallback) {
                        scaleCallback(item, itemSlot);
                        /**
                         * Количество айтемов в видимой части.
                         */ count++;
                    }
                }
            }
            if (scaleCallback && scaleResetCallback) {
                window.requestAnimationFrame(function() {
                    if (direction.current) {
                        if (nextItems.length) {
                            nextItems.splice(0, count).forEach(function(elem) {
                                return scaleCallback(elem, count);
                            });
                            if (nextItems.length) {
                                nextItems.splice(0, count).forEach(function(elem) {
                                    return scaleResetCallback(elem);
                                });
                            }
                        }
                    } else if (prevItems.length) {
                        var prItemsRev = prevItems.reverse();
                        prItemsRev.splice(0, count).forEach(function(elem) {
                            return scaleCallback(elem, count * -1);
                        });
                        if (prItemsRev.length) {
                            prItemsRev.splice(0, count).forEach(function(elem) {
                                return scaleResetCallback(elem);
                            });
                        }
                    }
                });
            }
        }, throttleMs);
    }, [
        axis,
        debouncedOnIndexChange,
        detectActive,
        detectThreshold,
        onDetectActiveItem,
        scaleCallback,
        scaleResetCallback,
        scrollAlign,
        throttleMs
    ]);
    /**
     * Прокрутка до нужной позиции индекса.
     */ var toIndex = (0, _react.useCallback)(function(i) {
        var scrollEl = scrollRef.current;
        var items = trackRef.current ? (0, _utils.getCarouselItems)(trackRef.current) : null;
        if (scrollEl && items && items.length > 0 && i >= 0) {
            (0, _utils.scrollToPos)({
                scrollEl: scrollEl,
                pos: (0, _utils.getCalculatedPos)({
                    scrollEl: scrollEl,
                    items: items,
                    axis: axis,
                    index: i,
                    offset: offset.current,
                    scrollAlign: scrollAlign
                }),
                axis: axis,
                /**
                     * Без анимации при переходе на другой конец списка
                     */ animated: animatedScrollByIndex && (prevIndex.current === null || Math.abs(i - prevIndex.current) !== items.length - 1)
            });
            prevIndex.current = i;
        }
    }, [
        animatedScrollByIndex,
        axis,
        scrollAlign
    ]);
    (0, _react.useEffect)(function() {
        if (scrollRef.current && trackRef.current) {
            offset.current = (0, _utils.getCalculatedOffset)(scrollRef.current, trackRef.current, axis);
        }
    }, [
        axis
    ]);
    /**
     * Операции на маунте/анмаунте компонента.
     * Создать слушатели событи и т.п.
     */ (0, _react.useEffect)(function() {
        var carouselElement = scrollRef.current;
        if (carouselElement) {
            carouselElement.addEventListener('scroll', throttledDetectActiveItem);
        }
        return function() {
            if (carouselElement) {
                carouselElement.removeEventListener('scroll', throttledDetectActiveItem);
            }
        };
    }, [
        throttledDetectActiveItem
    ]);
    /**
     * Нужно вызвать только при первом рендере
     */ (0, _react.useEffect)(function() {
        requestAnimationFrame(function() {
            /**
             * Прокрутка до начального индекса.
             */ toIndex(index);
            /**
             * Если на момент запуска карусель уже находится на нужной позиции,
             * событие скролла не произойдет, не сработает и определение центра,
             * необходимо вызвать его вручную.
             */ throttledDetectActiveItem();
        });
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);
    /**
     * Прокрутка до нужной позиции индекса, если индекс изменился.
     */ (0, _react.useEffect)(function() {
        if (index !== prevIndex.current) {
            toIndex(index);
        }
    }, [
        index,
        toIndex
    ]);
    return {
        scrollRef: scrollRef,
        trackRef: trackRef
    };
};
function useCarouselLite(param) {
    var index = param.index, axis = param.axis, _param_scrollAlign = param.scrollAlign, scrollAlign = _param_scrollAlign === void 0 ? 'center' : _param_scrollAlign, _param_scrollMode = param.scrollMode, scrollMode = _param_scrollMode === void 0 ? 'translate' : _param_scrollMode;
    var _useState = _sliced_to_array((0, _react.useState)(index), 2), prevIndex = _useState[0], setPrevIndex = _useState[1];
    var carouselRef = (0, _react.useRef)(null);
    var trackRef = (0, _react.useRef)(null);
    var needTranslateToInitialIndex = (0, _react.useRef)(true);
    // Первый раз нужно проскролить к индексу, после первого рендера
    (0, _react.useLayoutEffect)(function() {
        if (needTranslateToInitialIndex.current === false) {
            return;
        }
        /**
         * Вызываем через requestAnimationFrame, так как при использовании динамических CarouselCol
         * ширины элементов высчитываются неверно внутри translateToIndex при синхронном вызове
         */ var rafId = requestAnimationFrame(function() {
            (0, _utils.translateToIndex)(index, index, axis, scrollAlign, trackRef.current, carouselRef.current, true, scrollMode);
            needTranslateToInitialIndex.current = false;
        });
        return function() {
            cancelAnimationFrame(rafId);
        };
    }, [
        axis,
        index,
        scrollAlign,
        scrollMode
    ]);
    /**
     * Все последующие разы вызываем translateToIndex при изменении index прямо из рендера
     */ if (index !== prevIndex) {
        (0, _utils.translateToIndex)(index, prevIndex, axis, scrollAlign, trackRef.current, carouselRef.current, false, scrollMode);
        setPrevIndex(index);
    }
    return {
        scrollRef: carouselRef,
        trackRef: trackRef
    };
}
