/**
 * DevExtreme (esm/renovation/ui/scroll_view/animated_scrollbar.js)
 * Version: 21.1.4 (build 21182-0312)
 * Build date: Thu Jul 01 2021
 *
 * Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
import _extends from "@babel/runtime/helpers/esm/extends";
var _excluded = ["activeStateEnabled", "bottomPocketSize", "bounceEnabled", "containerSize", "contentSize", "contentTranslateOffsetChange", "defaultPocketState", "direction", "forceGeneratePockets", "forceUpdateScrollbarLocation", "forceVisibility", "hoverStateEnabled", "inertiaEnabled", "isScrollableHovered", "onAnimatorCancel", "onAnimatorStart", "onBounce", "onPullDown", "onReachBottom", "onRelease", "pocketState", "pocketStateChange", "pullDownEnabled", "reachBottomEnabled", "rtlEnabled", "scrollByThumb", "scrollLocation", "scrollLocationChange", "scrollableOffset", "showScrollbar", "topPocketSize"];
import {
    createComponentVNode
} from "inferno";
import {
    BaseInfernoComponent
} from "@devextreme/vdom";
import {
    isDefined
} from "../../../core/utils/type";
import devices from "../../../core/devices";
import {
    Scrollbar
} from "./scrollbar";
import {
    requestAnimationFrame,
    cancelAnimationFrame
} from "../../../animation/frame";
import {
    ScrollbarProps
} from "./scrollbar_props";
import {
    ScrollableSimulatedProps
} from "./scrollable_simulated_props";
import {
    ScrollableProps
} from "./scrollable_props";
export var OUT_BOUNDS_ACCELERATION = .5;
var isSluggishPlatform = "android" === devices.real().platform;
export var ACCELERATION = isSluggishPlatform ? .95 : .92;
export var MIN_VELOCITY_LIMIT = 1;
export var BOUNCE_MIN_VELOCITY_LIMIT = MIN_VELOCITY_LIMIT / 5;
var FRAME_DURATION = 17;
var BOUNCE_DURATION = isSluggishPlatform ? 300 : 400;
var BOUNCE_FRAMES = BOUNCE_DURATION / FRAME_DURATION;
export var BOUNCE_ACCELERATION_SUM = (1 - ACCELERATION ** BOUNCE_FRAMES) / (1 - ACCELERATION);
export var viewFunction = viewModel => {
    var {
        cancel: cancel,
        props: {
            bottomPocketSize: bottomPocketSize,
            bounceEnabled: bounceEnabled,
            containerSize: containerSize,
            contentSize: contentSize,
            contentTranslateOffsetChange: contentTranslateOffsetChange,
            direction: direction,
            forceGeneratePockets: forceGeneratePockets,
            forceUpdateScrollbarLocation: forceUpdateScrollbarLocation,
            isScrollableHovered: isScrollableHovered,
            onPullDown: onPullDown,
            onReachBottom: onReachBottom,
            onRelease: onRelease,
            pocketState: pocketState,
            pocketStateChange: pocketStateChange,
            pullDownEnabled: pullDownEnabled,
            reachBottomEnabled: reachBottomEnabled,
            rtlEnabled: rtlEnabled,
            scrollByThumb: scrollByThumb,
            scrollLocation: scrollLocation,
            scrollLocationChange: scrollLocationChange,
            scrollableOffset: scrollableOffset,
            showScrollbar: showScrollbar,
            topPocketSize: topPocketSize
        },
        scrollbarRef: scrollbarRef,
        start: start
    } = viewModel;
    return createComponentVNode(2, Scrollbar, {
        direction: direction,
        onAnimatorStart: start,
        onAnimatorCancel: cancel,
        scrollableOffset: scrollableOffset,
        contentSize: contentSize,
        containerSize: containerSize,
        isScrollableHovered: isScrollableHovered,
        scrollLocation: scrollLocation,
        scrollLocationChange: scrollLocationChange,
        contentTranslateOffsetChange: contentTranslateOffsetChange,
        scrollByThumb: scrollByThumb,
        bounceEnabled: bounceEnabled,
        showScrollbar: showScrollbar,
        forceUpdateScrollbarLocation: forceUpdateScrollbarLocation,
        rtlEnabled: rtlEnabled,
        forceGeneratePockets: forceGeneratePockets,
        topPocketSize: topPocketSize,
        bottomPocketSize: bottomPocketSize,
        onPullDown: onPullDown,
        onRelease: onRelease,
        onReachBottom: onReachBottom,
        pullDownEnabled: pullDownEnabled,
        reachBottomEnabled: reachBottomEnabled,
        pocketState: pocketState,
        pocketStateChange: pocketStateChange
    }, null, scrollbarRef)
};
export var AnimatedScrollbarProps = _extends({}, ScrollbarProps);
var AnimatedScrollbarPropsType = {
    activeStateEnabled: AnimatedScrollbarProps.activeStateEnabled,
    containerSize: AnimatedScrollbarProps.containerSize,
    contentSize: AnimatedScrollbarProps.contentSize,
    topPocketSize: AnimatedScrollbarProps.topPocketSize,
    bottomPocketSize: AnimatedScrollbarProps.bottomPocketSize,
    scrollableOffset: AnimatedScrollbarProps.scrollableOffset,
    isScrollableHovered: AnimatedScrollbarProps.isScrollableHovered,
    forceVisibility: AnimatedScrollbarProps.forceVisibility,
    forceUpdateScrollbarLocation: AnimatedScrollbarProps.forceUpdateScrollbarLocation,
    scrollLocation: AnimatedScrollbarProps.scrollLocation,
    onAnimatorCancel: AnimatedScrollbarProps.onAnimatorCancel,
    onPullDown: AnimatedScrollbarProps.onPullDown,
    onReachBottom: AnimatedScrollbarProps.onReachBottom,
    onRelease: AnimatedScrollbarProps.onRelease,
    defaultPocketState: AnimatedScrollbarProps.defaultPocketState,
    direction: ScrollableProps.direction,
    showScrollbar: ScrollableProps.showScrollbar,
    scrollByThumb: ScrollableProps.scrollByThumb,
    pullDownEnabled: ScrollableProps.pullDownEnabled,
    reachBottomEnabled: ScrollableProps.reachBottomEnabled,
    forceGeneratePockets: ScrollableProps.forceGeneratePockets,
    inertiaEnabled: ScrollableSimulatedProps.inertiaEnabled,
    bounceEnabled: ScrollableSimulatedProps.bounceEnabled
};
import {
    createRef as infernoCreateRef
} from "inferno";
export class AnimatedScrollbar extends BaseInfernoComponent {
    constructor(props) {
        super(props);
        this._currentState = null;
        this.scrollbarRef = infernoCreateRef();
        this.stepAnimationFrame = 0;
        this.finished = true;
        this.stopped = false;
        this.velocity = 0;
        this.animator = "inertia";
        this.state = {
            pocketState: void 0 !== this.props.pocketState ? this.props.pocketState : this.props.defaultPocketState
        };
        this.start = this.start.bind(this);
        this.cancel = this.cancel.bind(this);
        this.stepCore = this.stepCore.bind(this);
        this.getStepAnimationFrame = this.getStepAnimationFrame.bind(this);
        this.step = this.step.bind(this);
        this.setupBounce = this.setupBounce.bind(this);
        this.complete = this.complete.bind(this);
        this.stop = this.stop.bind(this);
        this.suppressInertia = this.suppressInertia.bind(this);
        this.crossBoundOnNextStep = this.crossBoundOnNextStep.bind(this);
        this.inBounds = this.inBounds.bind(this);
        this.getMaxOffset = this.getMaxOffset.bind(this);
        this.scrollStep = this.scrollStep.bind(this);
        this.moveTo = this.moveTo.bind(this);
        this.stopComplete = this.stopComplete.bind(this);
        this.scrollComplete = this.scrollComplete.bind(this);
        this.boundLocation = this.boundLocation.bind(this);
        this.getMinOffset = this.getMinOffset.bind(this);
        this.validateEvent = this.validateEvent.bind(this);
        this.isThumb = this.isThumb.bind(this);
        this.reachedMin = this.reachedMin.bind(this);
        this.reachedMax = this.reachedMax.bind(this);
        this.initHandler = this.initHandler.bind(this);
        this.startHandler = this.startHandler.bind(this);
        this.moveHandler = this.moveHandler.bind(this);
        this.endHandler = this.endHandler.bind(this);
        this.stopHandler = this.stopHandler.bind(this);
        this.scrollByHandler = this.scrollByHandler.bind(this);
        this.releaseHandler = this.releaseHandler.bind(this)
    }
    get __state_pocketState() {
        var state = this._currentState || this.state;
        return void 0 !== this.props.pocketState ? this.props.pocketState : state.pocketState
    }
    set_pocketState(value) {
        this.setState(state => {
            var _this$props$pocketSta, _this$props;
            this._currentState = state;
            var newValue = value();
            null === (_this$props$pocketSta = (_this$props = this.props).pocketStateChange) || void 0 === _this$props$pocketSta ? void 0 : _this$props$pocketSta.call(_this$props, newValue);
            this._currentState = null;
            return {
                pocketState: newValue
            }
        })
    }
    start(animatorName, receivedVelocity, thumbScrolling, crossThumbScrolling) {
        this.animator = animatorName;
        if (this.isBounceAnimator) {
            var _this$props$onBounce, _this$props2;
            null === (_this$props$onBounce = (_this$props2 = this.props).onBounce) || void 0 === _this$props$onBounce ? void 0 : _this$props$onBounce.call(_this$props2);
            this.setupBounce()
        } else {
            if (!thumbScrolling && crossThumbScrolling) {
                this.velocity = 0
            } else {
                this.velocity = receivedVelocity || 0
            }
            this.suppressInertia(thumbScrolling)
        }
        this.stopped = false;
        this.finished = false;
        this.stepCore()
    }
    cancel() {
        this.stopped = true;
        cancelAnimationFrame(this.stepAnimationFrame)
    }
    stepCore() {
        if (this.stopped) {
            this.stop();
            return
        }
        if (this.isFinished) {
            this.finished = true;
            this.complete();
            return
        }
        this.step();
        this.stepAnimationFrame = this.getStepAnimationFrame()
    }
    getStepAnimationFrame() {
        return requestAnimationFrame(this.stepCore)
    }
    step() {
        if (!this.props.bounceEnabled && !this.inBounds()) {
            this.velocity = 0
        }
        this.scrollStep(this.velocity);
        this.velocity *= this.acceleration
    }
    setupBounce() {
        var bounceDistance = this.boundLocation() - this.props.scrollLocation;
        this.velocity = bounceDistance / BOUNCE_ACCELERATION_SUM
    }
    complete() {
        if (this.isBounceAnimator) {
            this.moveTo(this.boundLocation())
        }
        this.scrollComplete()
    }
    get isBounceAnimator() {
        return "bounce" === this.animator
    }
    get isFinished() {
        if (this.isBounceAnimator) {
            return this.crossBoundOnNextStep() || Math.abs(this.velocity) <= BOUNCE_MIN_VELOCITY_LIMIT
        }
        return Math.abs(this.velocity) <= MIN_VELOCITY_LIMIT
    }
    get inProgress() {
        return !(this.stopped || this.finished)
    }
    get acceleration() {
        var _this$scrollbarRef;
        if (!isDefined(null === (_this$scrollbarRef = this.scrollbarRef) || void 0 === _this$scrollbarRef ? void 0 : _this$scrollbarRef.current)) {
            return 0
        }
        return this.inBounds() || this.isBounceAnimator ? ACCELERATION : OUT_BOUNDS_ACCELERATION
    }
    stop() {
        this.stopComplete()
    }
    suppressInertia(thumbScrolling) {
        if (!this.props.inertiaEnabled || thumbScrolling) {
            this.velocity = 0
        }
    }
    crossBoundOnNextStep() {
        var location = this.props.scrollLocation;
        var nextLocation = location + this.velocity;
        var minOffset = this.getMinOffset();
        var maxOffset = this.getMaxOffset();
        return location < minOffset && nextLocation >= minOffset || location > maxOffset && nextLocation <= maxOffset
    }
    inBounds() {
        var scrollbar = this.scrollbarRef.current;
        if (!isDefined(scrollbar)) {
            return false
        }
        return scrollbar.inBounds()
    }
    getMaxOffset() {
        return this.scrollbar.getMaxOffset()
    }
    scrollStep(delta) {
        this.scrollbar.scrollStep(delta)
    }
    moveTo(location) {
        this.scrollbar.moveTo(location)
    }
    stopComplete() {
        this.scrollbar.stopComplete()
    }
    scrollComplete() {
        this.scrollbar.scrollComplete()
    }
    get scrollbar() {
        return this.scrollbarRef.current
    }
    get restAttributes() {
        var _this$props$pocketSta2 = _extends({}, this.props, {
                pocketState: this.__state_pocketState
            }),
            restProps = _objectWithoutPropertiesLoose(_this$props$pocketSta2, _excluded);
        return restProps
    }
    boundLocation(value) {
        return this.scrollbar.boundLocation(value)
    }
    getMinOffset() {
        return this.scrollbar.getMinOffset()
    }
    validateEvent(e) {
        return this.scrollbar.validateEvent(e)
    }
    isThumb(element) {
        return this.scrollbar.isThumb(element)
    }
    reachedMin() {
        return this.scrollbar.reachedMin()
    }
    reachedMax() {
        return this.scrollbar.reachedMax()
    }
    initHandler(e, crossThumbScrolling) {
        this.scrollbar.initHandler(e, crossThumbScrolling)
    }
    startHandler() {
        this.scrollbar.startHandler()
    }
    moveHandler(delta) {
        this.scrollbar.moveHandler(delta)
    }
    endHandler(velocity) {
        this.scrollbar.endHandler(velocity)
    }
    stopHandler() {
        this.scrollbar.stopHandler()
    }
    scrollByHandler(delta) {
        this.scrollbar.scrollByHandler(delta)
    }
    releaseHandler() {
        this.scrollbar.releaseHandler()
    }
    render() {
        var props = this.props;
        return viewFunction({
            props: _extends({}, props, {
                pocketState: this.__state_pocketState
            }),
            scrollbarRef: this.scrollbarRef,
            start: this.start,
            cancel: this.cancel,
            stepCore: this.stepCore,
            getStepAnimationFrame: this.getStepAnimationFrame,
            step: this.step,
            setupBounce: this.setupBounce,
            complete: this.complete,
            isBounceAnimator: this.isBounceAnimator,
            isFinished: this.isFinished,
            inProgress: this.inProgress,
            acceleration: this.acceleration,
            stop: this.stop,
            suppressInertia: this.suppressInertia,
            crossBoundOnNextStep: this.crossBoundOnNextStep,
            inBounds: this.inBounds,
            getMaxOffset: this.getMaxOffset,
            scrollStep: this.scrollStep,
            moveTo: this.moveTo,
            stopComplete: this.stopComplete,
            scrollComplete: this.scrollComplete,
            scrollbar: this.scrollbar,
            restAttributes: this.restAttributes
        })
    }
}
AnimatedScrollbar.defaultProps = _extends({}, AnimatedScrollbarPropsType);
