import { animatedScrollToX, animatedScrollToY } from '../../utils';
var positionModByScrollAlign = function positionModByScrollAlign(param) {
    var scrollAlign = param.scrollAlign, position = param.position, carouselSize = param.carouselSize, itemSize = param.itemSize, offset = param.offset, scrollStart = param.scrollStart, axis = param.axis;
    if (scrollAlign === 'start') {
        var inaccuracy = 1;
        var paddingOffset = axis === 'y' ? offset - itemSize / 2 + inaccuracy : 0;
        return position + paddingOffset;
    }
    if (scrollAlign === 'center') {
        return position - carouselSize / 2 + itemSize / 2;
    }
    if (scrollAlign === 'end') {
        return position - carouselSize + itemSize + offset;
    }
    if (scrollAlign === 'activeDirection') {
        if (position >= scrollStart + carouselSize - itemSize) {
            return position - carouselSize + itemSize + offset;
        }
        if (position > scrollStart) {
            return scrollStart;
        }
    }
    return position;
};
/**
 * Подсчет скролла до переданного индекса.
 */ export var getCalculatedPos = function getCalculatedPos(param) {
    var scrollEl = param.scrollEl, items = param.items, axis = param.axis, index = param.index, offset = param.offset, scrollAlign = param.scrollAlign;
    var position = scrollAlign === 'center' ? offset : 0;
    var carouselSize;
    var itemSize;
    var scrollStart;
    if (items.item(index) === null) {
        return position;
    }
    for(var i = 0; i < index; i++){
        if (axis === 'x') {
            var _ref;
            var _items_item;
            position += (_ref = (_items_item = items.item(i)) === null || _items_item === void 0 ? void 0 : _items_item.offsetWidth) !== null && _ref !== void 0 ? _ref : 0;
        } else {
            var _ref1;
            var _items_item1;
            position += (_ref1 = (_items_item1 = items.item(i)) === null || _items_item1 === void 0 ? void 0 : _items_item1.offsetHeight) !== null && _ref1 !== void 0 ? _ref1 : 0;
        }
    }
    if (axis === 'x') {
        var _ref2;
        var _items_item2;
        carouselSize = scrollEl.offsetWidth;
        itemSize = (_ref2 = (_items_item2 = items.item(index)) === null || _items_item2 === void 0 ? void 0 : _items_item2.offsetWidth) !== null && _ref2 !== void 0 ? _ref2 : 0;
        scrollStart = scrollEl.scrollLeft;
    } else {
        var _ref3;
        var _items_item3;
        carouselSize = scrollEl.offsetHeight;
        itemSize = (_ref3 = (_items_item3 = items.item(index)) === null || _items_item3 === void 0 ? void 0 : _items_item3.offsetHeight) !== null && _ref3 !== void 0 ? _ref3 : 0;
        scrollStart = scrollEl.scrollTop;
    }
    return positionModByScrollAlign({
        scrollAlign: scrollAlign,
        position: position,
        carouselSize: carouselSize,
        itemSize: itemSize,
        offset: offset,
        scrollStart: scrollStart,
        axis: axis
    });
};
/**
 * Подсчет смещения из-за паддингов.
 */ export var getCalculatedOffset = function getCalculatedOffset(scrollEl, trackEl, axis) {
    var paddingProp = axis === 'x' ? 'paddingLeft' : 'paddingTop';
    return parseInt(getComputedStyle(scrollEl)[paddingProp], 10) + parseInt(getComputedStyle(trackEl)[paddingProp], 10);
};
/**
 * Прокрутка к указанной позиции с анимацией или без.
 */ export var scrollToPos = function scrollToPos(param) {
    var scrollEl = param.scrollEl, pos = param.pos, axis = param.axis, animated = param.animated, duration = param.duration, timingFunction = param.timingFunction;
    if (axis === 'x' && Math.abs(pos - scrollEl.scrollLeft) > 1) {
        if (animated) {
            animatedScrollToX(scrollEl, pos, duration, timingFunction);
        } else {
            scrollEl.scrollTo({
                left: pos
            });
        }
    }
    if (axis === 'y' && Math.abs(pos - scrollEl.scrollTop) > 1) {
        if (animated) {
            animatedScrollToY(scrollEl, pos, duration, timingFunction);
        } else {
            scrollEl.scrollTo({
                top: pos
            });
        }
    }
};
var round = function round(n) {
    return Math.round(n * 100) / 100;
};
/**
 * Получить позицию (слот) айтема в каруселе.
 * Каждый айтем имеет свой слот относительно вьюпорта карусели.
 */ export var getItemSlot = function getItemSlot(itemIndex, itemEnd, itemSize, scrollStart, scrollSize, scrollAlign) {
    var prevIndex = arguments.length > 6 && arguments[6] !== void 0 ? arguments[6] : 0, offset = arguments.length > 7 && arguments[7] !== void 0 ? arguments[7] : 0;
    /**
     * Граница и центр скролла (видимой части).
     * Смещение + размер.
     */ var scrollEnd = scrollStart + scrollSize;
    var scrollCenter = scrollStart + scrollSize / 2;
    var itemCenter = itemEnd - itemSize / 2;
    if (scrollAlign === 'center') {
        return round((itemCenter - scrollCenter) / itemSize);
    }
    if (scrollAlign === 'start') {
        return round((itemEnd - itemSize - scrollStart) / itemSize);
    }
    if (scrollAlign === 'end') {
        return round((itemEnd - (scrollSize + scrollStart)) / itemSize);
    }
    if (scrollAlign === 'activeDirection') {
        var prevStart = offset + itemSize * prevIndex;
        var prevEnd = prevStart + itemSize;
        var prevVisible = prevEnd > scrollStart && prevStart < scrollEnd;
        if (!prevVisible) {
            if (prevIndex < itemIndex) {
                return round((itemEnd - (scrollSize + scrollStart)) / itemSize);
            }
            return round((itemEnd - itemSize - scrollStart) / itemSize);
        }
    }
    return null;
};
export function getCarouselItems(track) {
    return track.children;
}
var axisToTranslateMap = {
    x: function x(position) {
        return "translateX(".concat(-position, "px)");
    },
    y: function y(position) {
        return "translateY(".concat(-position, "px)");
    }
};
var axisToOffsetKeyMap = {
    x: 'offsetLeft',
    y: 'offsetTop'
};
var axisToSizeKeyMap = {
    x: 'offsetWidth',
    y: 'offsetHeight'
};
var axisToScrollKeyMap = {
    x: 'scrollLeft',
    y: 'scrollTop'
};
function getCenterPosition(itemSize, itemStart, carouselSize, trackOffset) {
    var relativeMiddle = itemStart + trackOffset + itemSize / 2;
    return relativeMiddle - carouselSize / 2;
}
function getEndPosition(itemSize, itemStart, carouselSize, trackOffset) {
    return 2 * trackOffset + itemStart + itemSize - carouselSize;
}
function getTranslatePosition(itemSize, itemStart, carouselSize, trackOffset, scrollAlign) {
    switch(scrollAlign){
        case 'start':
            {
                return itemStart;
            }
        case 'end':
            {
                return getEndPosition(itemSize, itemStart, carouselSize, trackOffset);
            }
        case 'center':
        case 'activeDirection':
        default:
            return getCenterPosition(itemSize, itemStart, carouselSize, trackOffset);
    }
}
function boundPosition(position, trackSize, carouselSize, trackOffset) {
    if (position < 0) {
        return 0;
    }
    // если все элементы помещаются в ширину карусели, то считаем trackEnd по-другому
    if (trackSize < carouselSize) {
        var trackEnd = Math.abs(carouselSize - trackSize - trackOffset);
        return position < trackEnd ? position : trackEnd;
    }
    var trackEnd1 = trackSize - carouselSize + trackOffset;
    if (position > trackEnd1) {
        return trackEnd1;
    }
    return position;
}
/**
 * Функция решает являются ли переданные индексы крайними с начала и конца.
 * Например в такой карусели `([1][2][3][4])` — при изменении индекса с 4 на 1 или наоборот функция вернёт `true`,
 * так как это переход между крайними элементами.
 *
 * Есть исключение, для карусели длинной в 2 элемента `([1][2])`.
 * В этом случае переход с индекса 1 на 2 и наоборот не должен считаться переходом с одного края на другой.
 *
 * @param prevIndex
 * @param index
 * @param numberOfItems количество элементов в карусели
 */ function isMaximumDistance(prevIndex, index, numberOfItems) {
    // проверка, что карусель состоит из 2-х элементов
    if (numberOfItems === 2) {
        return false;
    }
    return Math.abs(index - prevIndex) === numberOfItems - 1;
}
function setTimingFunction(element, timingFunction) {
    if (element) {
        element.style.transitionTimingFunction = timingFunction;
    }
}
function translateToPosition(element, axis, position) {
    var translate = axisToTranslateMap[axis];
    element.style.transform = translate(position);
}
var scrollOptions = {
    behavior: 'auto',
    left: 0,
    top: 0
};
/**
 * Делает расчет следующей позиции карусели исходя из параметров
 * index, align и размеров элементов track и carousel.
 * После применяет transform к элементу track или вызывает scrollTo на элементе carousel.
 * При scrollMode равном translate Анимирование происходит из-за CSS свойства `transition-property: transform`,
 * применённому к элементу track
 *
 * @param index индекс элемента к которому нужно сделать transform
 * @param prevIndex индекс предыдущего активного элемента для расчёта дистанции между индексами
 * @param axis ось вдоль которой будет происходить transform
 * @param align определяет позицию активного элемента относительно элемента carousel
 * @param track элемент к которому применяется transform
 * @param carousel элемент содержащий track
 * @param disableAnimation флаг для отключения анимирования прокрутки
 * @param scrollMode прокрутка через scrollTo или через translate
 */ export function translateToIndex(index, prevIndex, axis, align, track, carousel, disableAnimation, scrollMode) {
    if (track === null || carousel === null) {
        return;
    }
    var scrollKey = axisToScrollKeyMap[axis];
    if (disableAnimation === false && scrollMode === 'translate' && carousel[scrollKey] !== 0) {
        carousel.scrollTo(scrollOptions);
    }
    var itemToTranslateTo = track.children.item(index);
    if (itemToTranslateTo === null) {
        return;
    }
    var numberOfItems = track.children.length;
    var offsetKey = axisToOffsetKeyMap[axis];
    var sizeKey = axisToSizeKeyMap[axis];
    var carouselSize = carousel[sizeKey];
    var trackSize = track[sizeKey];
    var trackOffset = track[offsetKey];
    var itemSize = itemToTranslateTo[sizeKey];
    var itemStart = itemToTranslateTo[offsetKey];
    var translatePosition = getTranslatePosition(itemSize, itemStart, carouselSize, trackOffset, align);
    var position = boundPosition(translatePosition, trackSize, carouselSize, trackOffset);
    if (scrollMode === 'scroll') {
        carousel.scrollTo({
            behavior: disableAnimation ? 'auto' : 'smooth',
            left: axis === 'x' ? position : 0,
            top: axis === 'y' ? position : 0
        });
        return;
    }
    if (disableAnimation === true || isMaximumDistance(prevIndex, index, numberOfItems) === true) {
        // Выключаем стандартный easing, переключая его на step-start
        setTimingFunction(track, 'step-start');
        translateToPosition(track, axis, position);
        /**
         * Включаем стандартный easing.
         * нужно делать через setTimeout, чтобы transform успел произойти до изменения transitionTimingFunction
         */ setTimeout(setTimingFunction, 0, track, '');
        return;
    }
    translateToPosition(track, axis, position);
}
