import { Host, h } from '@stencil/core';
/**
* Class that represent an autocomplete element
* composed by a textfield
* and a menu with selectable items for autocompletion
*/
export class Autocomplete {
    constructor() {
        /**
        * Apply low density on the element
        */
        this.dense = false;
        this.showSuggestions = false;
        this.selectedIndex = -1;
    }
    componentDidLoad() {
        this.watchValue();
        this.textElement.addEventListener('keydown', event => this.navigateSuggestions(event));
    }
    componentWillLoad() {
        this.watchValue();
    }
    watchValue() {
        if (this.value) {
            this.value.label = this.value.label ? this.value.label : this.value.value;
        }
        else {
            this.value = {
                value: null,
                label: null
            };
        }
    }
    navigateSuggestions(event) {
        if (this.suggestions && this.suggestions.size > 0) {
            let newIndex;
            const suggestionKeys = Array.from(this.suggestions.keys());
            switch (event.key) {
                case 'ArrowDown':
                    newIndex = this.selectedIndex !== null ? this.selectedIndex + 1 : 0;
                    if (newIndex >= this.suggestions.size) {
                        newIndex = 0;
                    }
                    this.selectedIndex = newIndex;
                    break;
                case 'ArrowUp':
                    newIndex = this.selectedIndex !== null ? this.selectedIndex - 1 : this.suggestions.size - 1;
                    if (newIndex < 0) {
                        newIndex = this.suggestions.size - 1;
                    }
                    this.selectedIndex = newIndex;
                    break;
                case 'Enter':
                    // Select first value with enter if none selected
                    if (this.selectedIndex === null) {
                        this.selectedIndex = 0;
                    }
                    this.selectSuggestion(suggestionKeys[this.selectedIndex]);
                    this.change.emit(this.value);
                    this.clearSuggestions();
                    return;
                default:
                    return;
            }
            event.preventDefault();
        }
    }
    clearSuggestions() {
        this.selectedIndex = -1;
        this.suggestions = null;
    }
    selectSuggestion(key) {
        this.showSuggestions = false;
        if (this.suggestions) {
            const newValue = {
                value: key,
                label: this.suggestions.get(key)
            };
            this.value = Object.assign({}, newValue);
        }
    }
    execAutocomplete(event) {
        this.value.label = event.target.value;
        this.autocomplete(event.target.value).then((suggests) => this.suggestions = suggests);
        this.showSuggestions = this.suggestions && this.suggestions.size > 0;
    }
    handleChange() {
        if (!this.textElement.value) {
            this.value = null;
            this.change.emit(this.value);
        }
        else {
            this.change.emit(this.value);
        }
    }
    render() {
        return (h(Host, { style: { 'position': 'relative' }, onBlur: () => {
                this.change.emit(this.value);
                this.showSuggestions = false;
            } },
            h("materials-text-field", { ref: el => this.textElement = el, "trailing-icon": this.trailingIcon, dense: this.dense, label: this.label, focused: !!this.value.label, value: this.value.label, onInput: (ev) => this.execAutocomplete(ev), onChange: (ev) => {
                    ev.stopPropagation();
                    ev.preventDefault();
                    this.handleChange();
                } }),
            this.showSuggestions &&
                h("materials-list", { style: { 'position': 'absolute', 'top': (this.textElement.getBoundingClientRect().bottom - this.textElement.getBoundingClientRect().top) + 'px' } }, Array.from(this.suggestions.keys()).map((key, index) => index < this.maxSuggestions ?
                    h("materials-list-item", { selected: index === this.selectedIndex, onClick: () => {
                            this.selectSuggestion(key);
                            this.change.emit(this.value);
                            this.clearSuggestions();
                        }, label: this.suggestions.get(key) }) : null))));
    }
    static get is() { return "materials-autocomplete"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() { return {
        "$": ["autocomplete.scss"]
    }; }
    static get styleUrls() { return {
        "$": ["autocomplete.css"]
    }; }
    static get properties() { return {
        "autocomplete": {
            "type": "unknown",
            "mutable": false,
            "complexType": {
                "original": "(search: string) => Promise<Map<string, string>>",
                "resolved": "(search: string) => Promise<Map<string, string>>",
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "Map": {
                        "location": "global"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Function of autocompletion to pass to the element\ncalled during onInput of the text-field"
            }
        },
        "value": {
            "type": "unknown",
            "mutable": true,
            "complexType": {
                "original": "{label?: string, value: string}",
                "resolved": "{ label?: string; value: string; }",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Value of the autocomplete text-field\ncomposed by a label to be displayed in the text-field\nand a value that is a real value\nif no label given, label = value"
            }
        },
        "dense": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Apply low density on the element"
            },
            "attribute": "dense",
            "reflect": false,
            "defaultValue": "false"
        },
        "label": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Label of the autocomplete"
            },
            "attribute": "label",
            "reflect": false
        },
        "trailingIcon": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Adds an icon at the end of the text field"
            },
            "attribute": "trailing-icon",
            "reflect": false
        },
        "maxSuggestions": {
            "type": "number",
            "mutable": false,
            "complexType": {
                "original": "number",
                "resolved": "number",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Limits the number of suggestions displayed in list"
            },
            "attribute": "max-suggestions",
            "reflect": false
        }
    }; }
    static get states() { return {
        "suggestions": {},
        "showSuggestions": {},
        "selectedIndex": {}
    }; }
    static get events() { return [{
            "method": "change",
            "name": "change",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Change event emitted when value is selected"
            },
            "complexType": {
                "original": "{label?: string, value: string}",
                "resolved": "{ label?: string; value: string; }",
                "references": {}
            }
        }]; }
    static get watchers() { return [{
            "propName": "value",
            "methodName": "watchValue"
        }]; }
}
