export var ScrollToDuration;
(function (ScrollToDuration) {
    ScrollToDuration["Long"] = "long";
    ScrollToDuration["Regular"] = "regular";
    ScrollToDuration["Fast"] = "fast";
    ScrollToDuration["Instant"] = "instant";
})(ScrollToDuration || (ScrollToDuration = {}));
var linear = function (t) { return t; };
// accelerating from zero velocity
var easeInQuad = function (t) { return t * t; };
// decelerating to zero velocity
var easeOutQuad = function (t) { return t * (2 - t); };
// accelerating from zero velocity
var easeInCubic = function (t) { return t * t * t; };
// decelerating to zero velocity
var easeOutCubic = function (t) { return --t * t * t + 1; };
// accelerating from zero velocity
var easeInQuint = function (t) { return t * t * t * t * t; };
// decelerating to zero velocity
var easeOutQuint = function (t) { return 1 + --t * t * t * t * t; };
var defaultEasingFunction = easeOutQuint;
var ScrollTo = /** @class */ (function () {
    function ScrollTo() {
    }
    /**
     * Scroll to top of the current windows
     *
     * @param duration duration of the scroll
     */
    ScrollTo.prototype.goToTop = function (duration) {
        if (duration === void 0) { duration = ScrollToDuration.Regular; }
        return this.internalScroll(undefined, 0, duration, defaultEasingFunction);
    };
    /**
     * Scroll to top of an specified container
     *
     * @param container the HTML container containing the scroll
     * @param duration duration of the scroll
     */
    ScrollTo.prototype.goToTopInside = function (container, duration) {
        if (duration === void 0) { duration = ScrollToDuration.Regular; }
        return this.internalScroll(container, 0, duration, defaultEasingFunction);
    };
    /**
     * Scroll to the bottom of an specified container
     *
     * @param container the HTML container containing the scroll
     * @param duration duration of the scroll
     */
    ScrollTo.prototype.goToBottomInside = function (container, duration) {
        if (duration === void 0) { duration = ScrollToDuration.Regular; }
        var targetLocation = this.maxContainerScroll(container);
        return this.internalScroll(container, targetLocation, duration, defaultEasingFunction);
    };
    /**
     * Scroll to the bottom of the windows
     *
     * @param duration duration of the scroll
     */
    ScrollTo.prototype.goToBottom = function (duration) {
        if (duration === void 0) { duration = ScrollToDuration.Regular; }
        var targetLocation = this.maxWindowScroll();
        return this.internalScroll(undefined, targetLocation, duration, defaultEasingFunction);
    };
    /**
     * Scroll to a specific element or position of the windows
     *
     * @param target the HTML container containing the scroll
     * @param offset the offset to add (in case of a sticky header)
     * @param duration duration of the scroll
     */
    ScrollTo.prototype.goTo = function (target, offset, duration) {
        if (duration === void 0) { duration = ScrollToDuration.Regular; }
        var targetLocation = 0;
        // get element relative position from window
        if (target instanceof HTMLElement) {
            var elementLocation = target.getBoundingClientRect().top + window.pageYOffset;
            targetLocation = Math.max(Math.round(elementLocation) + offset, 0);
        }
        else {
            targetLocation = +target;
        }
        // get scroll location if its less than maxscroll
        var scrollLocation = Math.min(targetLocation, this.maxWindowScroll());
        return this.internalScroll(undefined, scrollLocation, duration, defaultEasingFunction);
    };
    /**
     * Scroll to a specific element of an specified container
     *
     * @param container the HTML container containing the scroll
     * @param target the target HtmlElement
     * @param offset the offset to add (in case of a sticky header)
     * @param duration duration of the scroll
     * @param easing easing function to use
     */
    ScrollTo.prototype.goToInside = function (container, target, offset, duration) {
        if (duration === void 0) { duration = ScrollToDuration.Regular; }
        var targetLocation = 0;
        // get element relative position from container
        if (target instanceof HTMLElement) {
            var scrollTop = (container.getBoundingClientRect().top * -1) + container.scrollTop;
            targetLocation = (target.getBoundingClientRect().top + scrollTop) - container.clientTop;
            targetLocation = targetLocation + offset;
        }
        else {
            targetLocation = +target;
        }
        // get scroll location if its less than maxscroll
        var scrollLocation = Math.min(targetLocation, this.maxContainerScroll(container));
        return this.internalScroll(container, scrollLocation, duration, defaultEasingFunction);
    };
    ScrollTo.prototype.internalScroll = function (container, targetLocation, duration, easing) {
        var _this = this;
        return new Promise(function (resolve, reject) {
            var startTime = performance.now();
            var startLocation = 0;
            if (container) {
                _this.disableScrollEvent(container);
                startLocation = container.scrollTop;
            }
            else {
                _this.disableScrollEvent(document.body);
                startLocation = window.pageYOffset;
            }
            var distanceToScroll = targetLocation - startLocation;
            var _duration = _this.getDuration(duration);
            var step = function (currentTime) {
                var progressPercentage = _duration ? Math.min(1, ((currentTime - startTime) / _duration)) : 100;
                var targetPosition = _duration ? Math.floor(startLocation + distanceToScroll * easing(progressPercentage)) : targetLocation;
                if (container) {
                    container.scrollTop = targetPosition;
                    if (targetPosition === targetLocation || progressPercentage === 1) {
                        _this.enableScrollEvent(container);
                        return resolve(targetLocation);
                    }
                }
                else {
                    window.scrollTo(0, targetPosition);
                    if (Math.round(window.pageYOffset) === targetLocation || progressPercentage === 1) {
                        _this.enableScrollEvent(document.body);
                        return resolve(targetLocation);
                    }
                }
                window.requestAnimationFrame(step);
            };
            window.requestAnimationFrame(step);
        });
    };
    ScrollTo.prototype.disableScrollEvent = function (container) {
        container.addEventListener('touchmove', this.preventDefault, { passive: false });
        container.addEventListener('wheel', this.preventDefault, { passive: false });
        container.addEventListener('touchstart ', this.preventDefault, { passive: false });
    };
    ScrollTo.prototype.enableScrollEvent = function (container) {
        container.removeEventListener('touchmove', this.preventDefault);
        container.removeEventListener('wheel', this.preventDefault);
        container.removeEventListener('touchstart', this.preventDefault);
    };
    ScrollTo.prototype.preventDefault = function (e) {
        e.stopPropagation();
        e.preventDefault();
    };
    ScrollTo.prototype.maxContainerScroll = function (container) {
        return Math.max(Math.round(container.scrollHeight - container.offsetHeight), 0);
    };
    ScrollTo.prototype.maxWindowScroll = function () {
        return this.getDocumentHeight() - this.getWindowHeight();
    };
    ScrollTo.prototype.getDocumentHeight = function () {
        return Math.max(document.body.scrollHeight, document.documentElement ? document.documentElement.scrollHeight : 0, document.body.offsetHeight, document.documentElement ? document.documentElement.offsetHeight : 0, document.body.clientHeight, document.documentElement ? document.documentElement.clientHeight : 0);
    };
    ScrollTo.prototype.getWindowHeight = function () {
        return window.innerHeight ||
            (document.documentElement || document.body).clientHeight;
    };
    ScrollTo.prototype.getDuration = function (speed) {
        switch (speed) {
            case ScrollToDuration.Long:
                return 1000;
            case ScrollToDuration.Regular:
                return 600;
            case ScrollToDuration.Fast:
                return 400;
            case ScrollToDuration.Instant:
                return 0;
            default: throw Error('scrollToUtil: Unknown scroll duration.');
        }
    };
    return ScrollTo;
}());
export { ScrollTo };
var ScrollToPlugin = {
    install: function (v) {
        var scrollTo = new ScrollTo();
        (v.prototype).$scrollTo = scrollTo;
    }
};
export default ScrollToPlugin;
//# sourceMappingURL=scroll-to.js.map