import { __assign } from "tslib";
import { withThemeableProps } from '../../useThemeable';
import { classNamesFunction, css, KeyCodes } from '@uifabric-vue/utilities';
import Vue from 'vue';
import { Label } from '../Label';
var getClassNames = classNamesFunction();
export var ONKEYDOWN_TIMEOUT_DURATION = 1000;
export var SliderBase = Vue.extend({
    name: 'SliderBase',
    props: __assign(__assign({}, withThemeableProps()), { label: { type: String, default: null }, disabled: { type: Boolean, default: false }, vertical: { type: Boolean, default: false }, snapToStep: { type: Boolean, default: false }, min: { type: Number, default: 0 }, max: { type: Number, default: 10 }, step: { type: Number, default: 1 }, value: { type: Number, default: null }, defaultValue: { type: Number, default: null }, showValue: { type: Boolean, default: false }, originFromZero: { type: Boolean, default: false } }),
    data: function () {
        return {
            internalValue: this.value || this.defaultValue || this.min,
            renderedValue: this.value || this.defaultValue || this.min,
            onKeyDownTimer: -1,
        };
    },
    computed: {
        classNames: function () {
            var _a = this, className = _a.className, disabled = _a.disabled, vertical = _a.vertical, renderedValue = _a.renderedValue, internalValue = _a.internalValue, showValue = _a.showValue, theme = _a.theme;
            return getClassNames(this.styles, {
                className: className,
                disabled: disabled,
                vertical: vertical,
                showTransitions: renderedValue === internalValue,
                showValue: showValue,
                theme: theme,
            });
        },
        thumbOffsetPercent: function () {
            var _a = this, min = _a.min, max = _a.max, renderedValue = _a.renderedValue;
            return min === max ? 0 : ((renderedValue - min) / (max - min)) * 100;
        },
        zeroOffsetPercent: function () {
            var _a = this, min = _a.min, max = _a.max;
            return min >= 0 ? 0 : (-min / (max - min)) * 100;
        },
        lengthString: function () {
            return this.vertical ? 'height' : 'width';
        },
    },
    methods: {
        onMouseDown: function (event) {
            if (this.disabled)
                return;
            if (event.type === 'mousedown') {
                window.addEventListener('mousemove', this.onMove, true);
                window.addEventListener('mouseup', this.onMouseUp, true);
            }
            else if (event.type === 'touchstart') {
                window.addEventListener('touchmove', this.onMove, true);
                window.addEventListener('touchend', this.onMouseUp, true);
            }
            this.onMove(event);
        },
        onMouseUp: function (event) {
            if (this.disabled)
                return;
            this.renderedValue = this.internalValue;
            window.removeEventListener('mousemove', this.onMove, true);
            window.removeEventListener('mouseup', this.onMouseUp, true);
            window.removeEventListener('touchmove', this.onMove, true);
            window.removeEventListener('touchend', this.onMouseUp, true);
        },
        onMove: function (event) {
            var _this = this;
            window.requestAnimationFrame(function () {
                var _a = _this, max = _a.max, min = _a.min, step = _a.step, vertical = _a.vertical;
                var steps = (max - min) / step;
                var sliderPositionRect = _this.$refs.sliderLine.getBoundingClientRect();
                var sliderLength = !vertical
                    ? sliderPositionRect.width
                    : sliderPositionRect.height;
                var stepLength = sliderLength / steps;
                var currentSteps;
                var distance;
                if (!vertical) {
                    var left = _this.getPosition(event, vertical);
                    distance = left - sliderPositionRect.left;
                    currentSteps = distance / stepLength;
                }
                else {
                    var bottom = _this.getPosition(event, vertical);
                    distance = sliderPositionRect.bottom - bottom;
                    currentSteps = distance / stepLength;
                }
                var internalValue;
                var renderedValue;
                // The value shouldn't be bigger than max or be smaller than min.
                if (currentSteps > Math.floor(steps)) {
                    renderedValue = internalValue = max;
                }
                else if (currentSteps < 0) {
                    renderedValue = internalValue = min;
                }
                else {
                    renderedValue = min + step * currentSteps;
                    internalValue = min + step * Math.round(currentSteps);
                }
                _this.updateValue(internalValue, renderedValue);
            });
        },
        getPosition: function (event, vertical) {
            var currentPosition;
            switch (event.type) {
                case 'mousedown':
                case 'mousemove':
                    currentPosition = !vertical
                        ? event.clientX
                        : event.clientY;
                    break;
                case 'touchstart':
                case 'touchmove':
                    currentPosition = !vertical
                        ? event.touches[0].clientX
                        : event.touches[0].clientY;
                    break;
            }
            return currentPosition;
        },
        updateValue: function (value, renderedValue) {
            var _a = this, step = _a.step, snapToStep = _a.snapToStep;
            var numDec = 0;
            if (isFinite(step)) {
                while (Math.round(step * Math.pow(10, numDec)) / Math.pow(10, numDec) !== step) {
                    numDec++;
                }
            }
            // Make sure value has correct number of decimal places based on number of decimals in step
            var roundedValue = parseFloat(value.toFixed(numDec));
            var valueChanged = roundedValue !== this.internalValue;
            if (snapToStep) {
                renderedValue = roundedValue;
            }
            this.internalValue = roundedValue;
            this.renderedValue = renderedValue;
            this.$emit('input', roundedValue);
        },
        onKeyDown: function (event) {
            var value = this.internalValue;
            var _a = this, max = _a.max, min = _a.min, step = _a.step;
            var diff = 0;
            switch (event.which) {
                case KeyCodes.left:
                case KeyCodes.down:
                    diff = -step;
                    this.clearOnKeyDownTimer();
                    this.setOnKeyDownTimer(event);
                    break;
                case KeyCodes.right:
                case KeyCodes.up:
                    diff = step;
                    this.clearOnKeyDownTimer();
                    this.setOnKeyDownTimer(event);
                    break;
                case KeyCodes.home:
                    value = min;
                    break;
                case KeyCodes.end:
                    value = max;
                    break;
                default:
                    return;
            }
            var newValue = Math.min(max, Math.max(min, value + diff));
            this.updateValue(newValue, newValue);
            event.preventDefault();
            event.stopPropagation();
        },
        clearOnKeyDownTimer: function () {
            clearTimeout(this.onKeyDownTimer);
        },
        setOnKeyDownTimer: function (event) {
            this.onKeyDownTimer = setTimeout(function () {
            }, ONKEYDOWN_TIMEOUT_DURATION);
        },
    },
    render: function (h) {
        var _a, _b, _c, _d, _e, _f, _g;
        var _h, _j, _k;
        var _l = this, classNames = _l.classNames, disabled = _l.disabled, originFromZero = _l.originFromZero, vertical = _l.vertical, zeroOffsetPercent = _l.zeroOffsetPercent, thumbOffsetPercent = _l.thumbOffsetPercent, lengthString = _l.lengthString, internalValue = _l.internalValue, label = _l.label;
        var $sliderLine = h('div', {
            ref: 'sliderLine',
            class: classNames.line,
        }, [
            originFromZero && h('span', {
                class: classNames.zeroTick,
                style: (_a = {}, _a[vertical ? 'bottom' : 'left'] = "".concat(zeroOffsetPercent, "%"), _a),
            }),
            h('span', {
                class: classNames.thumb,
                style: (_b = {}, _b[vertical ? 'bottom' : 'left'] = "".concat(thumbOffsetPercent, "%"), _b),
            }),
            originFromZero && h('span', {
                class: css(classNames.lineContainer, classNames.inactiveSection),
                style: (_c = {}, _c[lengthString] = "".concat(Math.min(thumbOffsetPercent, zeroOffsetPercent), "%"), _c),
            }),
            originFromZero && h('span', {
                class: css(classNames.lineContainer, classNames.activeSection),
                style: (_d = {}, _d[lengthString] = "".concat(Math.abs(zeroOffsetPercent - thumbOffsetPercent), "%"), _d),
            }),
            originFromZero && h('span', {
                class: css(classNames.lineContainer, classNames.inactiveSection),
                style: (_e = {}, _e[lengthString] = "".concat(Math.min(100 - thumbOffsetPercent, 100 - zeroOffsetPercent), "%"), _e),
            }),
            !originFromZero && h('span', {
                class: css(classNames.lineContainer, classNames.activeSection),
                style: (_f = {}, _f[lengthString] = "".concat(thumbOffsetPercent, "%"), _f),
            }),
            !originFromZero && h('span', {
                class: css(classNames.lineContainer, classNames.inactiveSection),
                style: (_g = {}, _g[lengthString] = "".concat(100 - thumbOffsetPercent, "%"), _g),
            }),
        ]);
        var $valueLabel = h(Label, {
            class: classNames.valueLabel,
        }, (_k = (_j = (_h = this.$scopedSlots).value) === null || _j === void 0 ? void 0 : _j.call(_h, { value: internalValue })) !== null && _k !== void 0 ? _k : "".concat(internalValue));
        return h('div', { class: classNames.root }, [
            h(Label, { class: classNames.titleLabel }, label),
            h('div', { class: classNames.container }, [
                h('div', {
                    class: classNames.slideBox,
                    attrs: {
                        tabindenx: disabled ? undefined : 0,
                    },
                    on: {
                        mousedown: this.onMouseDown,
                        keydown: this.onKeyDown,
                    },
                }, [
                    $sliderLine,
                ]),
                $valueLabel,
            ]),
        ]);
    },
});
//# sourceMappingURL=Slider.base.js.map