import { vglobal } from "@visactor/vrender-core";

import { merge, normalizePadding, clamp, clampRange, debounce, throttle } from "@visactor/vutils";

import { AbstractComponent } from "../core/base";

import { loadScrollbarComponent } from "./register";

import { SCROLLBAR_START_EVENT, SCROLLBAR_EVENT, SCROLLBAR_END_EVENT } from "../constant";

import { getEndTriggersOfDrag } from "../util/event";

const delayMap = {
    debounce: debounce,
    throttle: throttle
};

loadScrollbarComponent();

export class ScrollBar extends AbstractComponent {
    constructor(attributes, options) {
        super((null == options ? void 0 : options.skipDefault) ? attributes : merge({}, ScrollBar.defaultAttributes, attributes)), 
        this.name = "scrollbar", this._onRailPointerDown = e => {
            const {viewX: viewX, viewY: viewY} = e, {direction: direction, width: width, height: height, range: range} = this.attribute, sliderSize = this._sliderSize, [min, max] = this._getScrollRange();
            let currentScrollValue;
            if ("vertical" === direction) {
                const relativeY = viewY - this._viewPosition.y, currentYPos = clamp(relativeY - sliderSize / 2, min, max);
                currentScrollValue = relativeY / height, this._slider.setAttribute("y", currentYPos, !0);
            } else {
                const relativeX = viewX - this._viewPosition.x, currentXPos = clamp(relativeX - sliderSize / 2, min, max);
                currentScrollValue = relativeX / width, this._slider.setAttribute("x", currentXPos, !0);
            }
            this.setScrollRange([ currentScrollValue - (range[1] - range[0]) / 2, currentScrollValue + (range[1] - range[0]) / 2 ], !1), 
            this.stage && !this.stage.autoRender && this.stage.renderNextFrame();
        }, this._onSliderPointerDown = e => {
            this._clearDragEvents();
            const {stopSliderDownPropagation: stopSliderDownPropagation = !0} = this.attribute;
            stopSliderDownPropagation && e.stopPropagation();
            const {direction: direction} = this.attribute, {x: x, y: y} = this.stage.eventPointTransform(e);
            this._prePos = "horizontal" === direction ? x : y, this._dispatchEvent(SCROLLBAR_START_EVENT, {
                pos: this._prePos,
                event: e
            });
            const triggers = getEndTriggersOfDrag(), obj = "browser" === vglobal.env ? vglobal : this.stage;
            obj.addEventListener("pointermove", this._onSliderPointerMoveWithDelay, {
                capture: !0,
                passive: !0
            }), triggers.forEach((trigger => {
                obj.addEventListener(trigger, this._onSliderPointerUp);
            }));
        }, this._computeScrollValue = e => {
            const {direction: direction} = this.attribute, {x: x, y: y} = this.stage.eventPointTransform(e);
            let currentScrollValue, currentPos, delta = 0;
            const {width: width, height: height} = this.getSliderRenderBounds();
            return "vertical" === direction ? (currentPos = y, delta = currentPos - this._prePos, 
            currentScrollValue = delta / height) : (currentPos = x, delta = currentPos - this._prePos, 
            currentScrollValue = delta / width), [ currentPos, currentScrollValue ];
        }, this._onSliderPointerMove = e => {
            e.preventDefault();
            const {stopSliderMovePropagation: stopSliderMovePropagation = !0} = this.attribute;
            stopSliderMovePropagation && e.stopPropagation();
            const preScrollRange = this.getScrollRange(), [currentPos, currentScrollValue] = this._computeScrollValue(e);
            this.setScrollRange([ preScrollRange[0] + currentScrollValue, preScrollRange[1] + currentScrollValue ], !0), 
            this._prePos = currentPos;
        }, this._onSliderPointerMoveWithDelay = 0 === this.attribute.delayTime ? this._onSliderPointerMove : delayMap[this.attribute.delayType](this._onSliderPointerMove, this.attribute.delayTime), 
        this._onSliderPointerUp = e => {
            const {range: preRange, limitRange: limitRange = [ 0, 1 ]} = this.attribute, preScrollRange = this.getScrollRange(), [currentPos, currentScrollValue] = this._computeScrollValue(e), range = [ preScrollRange[0] + currentScrollValue, preScrollRange[1] + currentScrollValue ];
            this._dispatchEvent(SCROLLBAR_END_EVENT, {
                pre: preRange,
                value: clampRange(range, limitRange[0], limitRange[1])
            }), this._clearDragEvents();
        };
    }
    setScrollRange(range, render = !0) {
        const {direction: direction = "horizontal", limitRange: limitRange = [ 0, 1 ], range: preRange, realTime: realTime = !0} = this.attribute, currScrollRange = clampRange(range, limitRange[0], limitRange[1]);
        if (render) {
            const sliderPos = this._getSliderPos(currScrollRange);
            if (this._slider) {
                const sliderSize = sliderPos[1] - sliderPos[0];
                this._sliderSize = sliderSize, "horizontal" === direction ? this._slider.setAttributes({
                    x: sliderPos[0],
                    width: sliderSize
                }, !0) : this._slider.setAttributes({
                    y: sliderPos[0],
                    height: sliderSize
                }, !0), this.stage && !this.stage.autoRender && this.stage.renderNextFrame();
            }
        }
        this.attribute.range = currScrollRange, realTime && this._dispatchEvent(SCROLLBAR_EVENT, {
            pre: preRange,
            value: currScrollRange
        });
    }
    getScrollRange() {
        return this.attribute.range;
    }
    bindEvents() {
        if (this.attribute.disableTriggerEvent) return;
        const {delayType: delayType = "throttle", delayTime: delayTime = 0} = this.attribute;
        this._rail && this._rail.addEventListener("pointerdown", delayMap[delayType](this._onRailPointerDown, delayTime)), 
        this._slider && this._slider.addEventListener("pointerdown", this._onSliderPointerDown);
    }
    render() {
        this._reset();
        const {direction: direction = "horizontal", width: width, height: height, range: range, limitRange: limitRange = [ 0, 1 ], railStyle: railStyle, sliderStyle: sliderStyle, padding: padding = 2} = this.attribute, group = this.createOrUpdateChild("scrollbar-container", {}, "group"), rail = group.createOrUpdateChild("scrollbar-rail", Object.assign({
            x: 0,
            y: 0,
            width: width,
            height: height
        }, railStyle), "rect");
        this._rail = rail;
        const sliderRenderBounds = this.getSliderRenderBounds(), sliderPos = this._getSliderPos(clampRange(range, limitRange[0], limitRange[1])), sliderSize = sliderPos[1] - sliderPos[0];
        let sliderAttribute;
        this._sliderSize = sliderSize, sliderAttribute = "horizontal" === direction ? {
            x: sliderPos[0],
            y: sliderRenderBounds.y1,
            width: sliderSize,
            height: sliderRenderBounds.height
        } : {
            x: sliderRenderBounds.x1,
            y: sliderPos[0],
            width: sliderRenderBounds.width,
            height: sliderSize
        };
        const slider = group.createOrUpdateChild("slider", Object.assign(Object.assign(Object.assign(Object.assign({}, sliderAttribute), {
            cornerRadius: this._getDefaultSliderCornerRadius()
        }), sliderStyle), {
            boundsPadding: normalizePadding(padding),
            pickMode: "imprecise"
        }), "rect");
        this._slider = slider, this._container = group;
        const containerAABBBounds = this._container.AABBBounds;
        this._viewPosition = {
            x: containerAABBBounds.x1,
            y: containerAABBBounds.y1
        };
    }
    getSliderRenderBounds() {
        if (this._sliderRenderBounds) return this._sliderRenderBounds;
        const {width: width, height: height, padding: padding = 2} = this.attribute, [top, right, bottom, left] = normalizePadding(padding), renderBounds = {
            x1: left,
            y1: top,
            x2: width - right,
            y2: height - bottom,
            width: Math.max(0, width - (left + right)),
            height: Math.max(0, height - (top + bottom))
        };
        return this._sliderRenderBounds = renderBounds, renderBounds;
    }
    _getDefaultSliderCornerRadius() {
        const {direction: direction, round: round} = this.attribute;
        if (round) {
            const {width: width, height: height} = this.getSliderRenderBounds();
            return "horizontal" === direction ? height : width;
        }
        return 0;
    }
    _getSliderPos(range) {
        const {direction: direction} = this.attribute, {width: width, height: height, x1: x1, y1: y1} = this.getSliderRenderBounds();
        return "horizontal" === direction ? [ width * range[0] + x1, width * range[1] + x1 ] : [ height * range[0] + y1, height * range[1] + y1 ];
    }
    _getScrollRange() {
        if (this._sliderLimitRange) return this._sliderLimitRange;
        const {limitRange: limitRange = [ 0, 1 ], direction: direction} = this.attribute, [min, max] = clampRange(limitRange, 0, 1), {width: width, height: height, x1: x1, y1: y1} = this.getSliderRenderBounds(), sliderSize = this._sliderSize;
        return "horizontal" === direction ? clampRange([ x1 + min * width, x1 + max * width ], x1, width - sliderSize) : clampRange([ y1 + min * height, y1 + max * height ], y1, height - sliderSize);
    }
    _clearDragEvents() {
        const triggers = getEndTriggersOfDrag(), obj = "browser" === vglobal.env ? vglobal : this.stage;
        obj.removeEventListener("pointermove", this._onSliderPointerMoveWithDelay, {
            capture: !0,
            passive: !1
        }), triggers.forEach((trigger => {
            obj.removeEventListener(trigger, this._onSliderPointerUp);
        }));
    }
    _reset() {
        this._sliderRenderBounds = null, this._sliderLimitRange = null;
    }
}

ScrollBar.defaultAttributes = {
    direction: "horizontal",
    round: !0,
    sliderSize: 20,
    sliderStyle: {
        fill: "rgba(0, 0, 0, .5)"
    },
    railStyle: {
        fill: "rgba(0, 0, 0, .0)"
    },
    padding: 2,
    scrollRange: [ 0, 1 ],
    delayType: "throttle",
    delayTime: 0,
    realTime: !0
};
//# sourceMappingURL=scrollbar.js.map
