import { MDCSlider } from "@material/slider";
import { h, Host, } from "@stencil/core";
import { getPercentageClass } from "./get-percentage-class";
import { createRandomString } from "../../util/random-string";
const DEFAULT_FACTOR = 1;
const DEFAULT_MAX_VALUE = 100;
const DEFAULT_MIN_VALUE = 0;
/**
 * @exampleComponent limel-example-slider-basic
 * @exampleComponent limel-example-slider-multiplier
 * @exampleComponent limel-example-slider-multiplier-percentage-colors
 * @exampleComponent limel-example-slider-composite
 */
export class Slider {
    constructor() {
        /**
         * Disables the slider when `true`,
         * and visually shows that the field is editable but disabled.
         * This tells the users that if certain requirements are met,
         * the slider may become interactable.
         */
        this.disabled = false;
        /**
         * Disables the slider when `true`. This visualizes the slider slightly differently.
         * But shows no visual sign indicating that the slider field
         * is disabled or can ever become interactable.
         */
        this.readonly = false;
        /**
         * Default value: 1.
         * The factor that the properties `value`, `valuemax`, `valuemin`, and
         * `step` are multiplied by. On `change` divides the value by the factor,
         * so the original format stays the same.
         */
        this.factor = DEFAULT_FACTOR;
        /**
         * Set to `true` to indicate that the slider is required.
         */
        this.required = false;
        /**
         * Set to `true` to indicate that the current value of the slider is invalid.
         */
        this.invalid = false;
        /**
         * Set to `true` to display percentage-based colors on the slider.
         * The colors change in intervals of 10% as the value changes,
         * creating a color spectrum from red (low) → orange → yellow → green → teal (high).
         */
        this.displaysPercentageColors = false;
        /**
         * Unit to display next to the value
         */
        this.unit = '';
        /**
         * The maximum value allowed
         */
        this.valuemax = DEFAULT_MAX_VALUE;
        /**
         * The minimum value allowed
         */
        this.valuemin = DEFAULT_MIN_VALUE;
        this.renderRangeContainer = () => {
            return (h("div", { class: "slider__content-range-container" }, h("span", { class: "slider__content-min-label" }, this.multiplyByFactor(this.valuemin), this.unit), h("span", { class: "slider__content-max-label" }, this.multiplyByFactor(this.valuemax), this.unit)));
        };
        this.renderSliderContainer = (inputProps) => {
            return (h("div", { class: {
                    'mdc-slider': true,
                    'mdc-slider--discrete': true,
                    'mdc-slider--disabled': this.disabled || this.readonly,
                } }, this.renderSliderInput(inputProps), this.renderTrack(), this.renderThumb()));
        };
        this.renderSliderInput = (inputProps) => {
            return (h("input", Object.assign({ class: "mdc-slider__input", type: "range", min: this.multiplyByFactor(this.valuemin), max: this.multiplyByFactor(this.valuemax), value: this.multiplyByFactor(this.value), name: "volume", "aria-labelledby": this.labelId, "aria-describedby": this.helperText ? this.helperTextId : undefined, "aria-controls": this.helperText ? this.helperTextId : undefined }, inputProps)));
        };
        this.renderTrack = () => {
            return (h("div", { class: "mdc-slider__track" }, h("div", { class: "mdc-slider__track--inactive" }), h("div", { class: "mdc-slider__track--active" }, h("div", { class: "mdc-slider__track--active_fill" }))));
        };
        this.renderThumb = () => {
            return (h("div", { class: "mdc-slider__thumb" }, h("div", { class: "mdc-slider__value-indicator-container", "aria-hidden": "true" }, h("div", { class: "mdc-slider__value-indicator" }, h("span", { class: "mdc-slider__value-indicator-text" }, this.multiplyByFactor(this.value)))), h("div", { class: "mdc-slider__thumb-knob" })));
        };
        this.renderHelperLine = () => {
            if (!this.helperText) {
                return;
            }
            return (h("limel-helper-line", { helperText: this.helperText, helperTextId: this.helperTextId, invalid: this.invalid }));
        };
        this.initialize = () => {
            const inputElement = this.getInputElement();
            if (!inputElement) {
                return;
            }
            const value = this.getValue();
            /*
            For some reason the input element's `value` attribute is removed
            (probably by Stencil) when the element is first rendered. But if the
            attribute is missing when MDCSlider is initialized (MDC v11.0.0),
            MDCSlider crashes.
            So we add the attribute right before initializing MDCSlider. /Ads
            */
            inputElement.setAttribute('value', `${this.multiplyByFactor(value)}`);
            /*
            When creating the `mdcSlider` component, its important that the value set in
            the input field obeys the range and the step size.
    
            The MDCSlider will throw an exception unless the value in the input element
            is dividible by the step value and is in the provided range.
            If an exception occurs, this component will crash and it will be impossible to change
            its value.
            The logic below ensures that the component will render even though the
            provided value is wrong.
            This could be considered wrong, but it at least fixes so that it's possible
            to change the value from the UI.
            */
            const greaterThanOrEqualMin = value >= this.valuemin;
            const lessThanOrEqualMax = value <= this.valuemax;
            if (!greaterThanOrEqualMin) {
                const newMin = this.multiplyByFactor(value);
                inputElement.setAttribute('min', `${newMin}`);
            }
            if (!lessThanOrEqualMax) {
                const newMax = this.multiplyByFactor(value);
                inputElement.setAttribute('max', `${newMax}`);
            }
            if (!this.isMultipleOfStep(value, this.step)) {
                inputElement.removeAttribute('step');
            }
            this.createMDCSlider();
        };
        this.reCreateSliderWithStep = () => {
            const inputElement = this.getInputElement();
            const step = `${this.multiplyByFactor(this.step)}`;
            inputElement.setAttribute('step', step);
            this.destroyMDCSlider();
            this.createMDCSlider();
        };
        this.createMDCSlider = () => {
            const element = this.getRootElement();
            this.mdcSlider = new MDCSlider(element);
            this.mdcSlider.listen('MDCSlider:change', this.changeHandler);
            this.mdcSlider.listen('MDCSlider:input', this.inputHandler);
        };
        this.changeHandler = (event) => {
            let value = event.detail.value;
            const step = this.multiplyByFactor(this.step);
            if (!this.isMultipleOfStep(value, step)) {
                value = this.roundToStep(value, step);
            }
            this.change.emit(value / this.factor);
        };
        this.inputHandler = (event) => {
            this.setPercentageClass(event.detail.value / this.factor);
        };
        this.getContainerClassList = () => {
            return {
                [this.percentageClass]: true,
                'displays-percentage-colors': this.displaysPercentageColors,
                disabled: this.disabled || this.readonly,
                readonly: this.readonly,
            };
        };
        this.resizeObserverCallback = () => {
            var _a;
            (_a = this.mdcSlider) === null || _a === void 0 ? void 0 : _a.layout();
        };
        this.updateDisabledState = () => {
            var _a;
            if (!this.mdcSlider) {
                return;
            }
            (_a = this.mdcSlider) === null || _a === void 0 ? void 0 : _a.setDisabled(this.disabled || this.readonly);
        };
        this.multiplyByFactor = (value) => {
            return Math.round(value * this.factor);
        };
        this.getValue = () => {
            let value = this.value;
            if (!Number.isFinite(value)) {
                value = this.valuemin;
            }
            return value;
        };
        this.setPercentageClass = (value) => {
            this.percentageClass = getPercentageClass((value - this.valuemin) / (this.valuemax - this.valuemin));
        };
        this.isMultipleOfStep = (value, step) => {
            if (!step) {
                return true;
            }
            return value % step === 0;
        };
        this.roundToStep = (value, step) => {
            return Math.round(value / step) * step;
        };
        this.getRootElement = () => {
            return this.rootElement.shadowRoot.querySelector('.mdc-slider');
        };
        this.getInputElement = () => {
            const element = this.getRootElement();
            if (!element) {
                return;
            }
            return element.querySelector('input');
        };
        this.isStepConfigured = () => {
            if (!this.step) {
                return true;
            }
            const input = this.getInputElement();
            if (!input) {
                return true;
            }
            return input.hasAttribute('step');
        };
        this.labelId = createRandomString();
        this.helperTextId = createRandomString();
    }
    connectedCallback() {
        this.initialize();
        this.observer = new ResizeObserver(this.resizeObserverCallback);
        this.observer.observe(this.rootElement);
    }
    componentWillLoad() {
        this.setPercentageClass(this.value);
    }
    componentDidLoad() {
        this.initialize();
    }
    disconnectedCallback() {
        this.destroyMDCSlider();
        this.observer.disconnect();
    }
    render() {
        const inputProps = {};
        if (this.step) {
            inputProps.step = this.multiplyByFactor(this.step);
        }
        if (this.disabled || this.readonly) {
            inputProps.disabled = true;
        }
        return (h(Host, { key: 'cf07e4288eae4c909632d74fe77e6a827b122abb', class: this.getContainerClassList() }, h("limel-notched-outline", { key: '23ed21c06dea5c581ec9d8cdf2dcfea767417e2f', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid, disabled: this.disabled, readonly: this.readonly, hasValue: !!this.value, hasFloatingLabel: true }, h("div", { key: 'afdaaa1f8b4d0ceeebb3eca73649849f871dff69', slot: "content" }, this.renderRangeContainer(), this.renderSliderContainer(inputProps))), this.renderHelperLine()));
    }
    watchDisabled() {
        this.updateDisabledState();
    }
    watchReadonly() {
        this.updateDisabledState();
    }
    watchValue() {
        if (!this.mdcSlider) {
            return;
        }
        const value = this.multiplyByFactor(this.getValue());
        this.mdcSlider.setValue(value);
        if (this.isStepConfigured()) {
            return;
        }
        const step = this.multiplyByFactor(this.step);
        if (!this.isMultipleOfStep(value, step)) {
            return;
        }
        this.reCreateSliderWithStep();
    }
    destroyMDCSlider() {
        this.mdcSlider.unlisten('MDCSlider:change', this.changeHandler);
        this.mdcSlider.unlisten('MDCSlider:input', this.inputHandler);
        this.mdcSlider.destroy();
        this.mdcSlider = undefined;
    }
    static get is() { return "limel-slider"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["slider.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["slider.css"]
        };
    }
    static get properties() {
        return {
            "disabled": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Disables the slider when `true`,\nand visually shows that the field is editable but disabled.\nThis tells the users that if certain requirements are met,\nthe slider may become interactable."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "disabled",
                "defaultValue": "false"
            },
            "readonly": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Disables the slider when `true`. This visualizes the slider slightly differently.\nBut shows no visual sign indicating that the slider field\nis disabled or can ever become interactable."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "readonly",
                "defaultValue": "false"
            },
            "factor": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Default value: 1.\nThe factor that the properties `value`, `valuemax`, `valuemin`, and\n`step` are multiplied by. On `change` divides the value by the factor,\nso the original format stays the same."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "factor",
                "defaultValue": "DEFAULT_FACTOR"
            },
            "label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Label to display next to the input"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "label"
            },
            "helperText": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Optional helper text to display below the slider"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "helper-text"
            },
            "required": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Set to `true` to indicate that the slider is required."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "required",
                "defaultValue": "false"
            },
            "invalid": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Set to `true` to indicate that the current value of the slider is invalid."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "invalid",
                "defaultValue": "false"
            },
            "displaysPercentageColors": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Set to `true` to display percentage-based colors on the slider.\nThe colors change in intervals of 10% as the value changes,\ncreating a color spectrum from red (low) \u2192 orange \u2192 yellow \u2192 green \u2192 teal (high)."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "displays-percentage-colors",
                "defaultValue": "false"
            },
            "unit": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Unit to display next to the value"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "unit",
                "defaultValue": "''"
            },
            "value": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The value of the input"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "value"
            },
            "valuemax": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The maximum value allowed"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "valuemax",
                "defaultValue": "DEFAULT_MAX_VALUE"
            },
            "valuemin": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The minimum value allowed"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "valuemin",
                "defaultValue": "DEFAULT_MIN_VALUE"
            },
            "step": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The stepping interval to use when adjusting the value"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "step"
            }
        };
    }
    static get states() {
        return {
            "percentageClass": {}
        };
    }
    static get events() {
        return [{
                "method": "change",
                "name": "change",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the value has been changed"
                },
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                }
            }];
    }
    static get elementRef() { return "rootElement"; }
    static get watchers() {
        return [{
                "propName": "disabled",
                "methodName": "watchDisabled"
            }, {
                "propName": "readonly",
                "methodName": "watchReadonly"
            }, {
                "propName": "value",
                "methodName": "watchValue"
            }];
    }
}
