import { select, option, optgroup, empty } from "../../core/dom";
import { isString, isArray } from "../../core/util/types";
import { entries } from "../../core/util/object";
import { InputWidget, InputWidgetView } from "./input_widget";
import * as inputs from "../../styles/widgets/inputs.css";
import { Unknown, Str, List, Tuple, Or, Dict } from "../../core/kinds";
const Value = Unknown;
const Label = Str;
const Options = List(Or(Label, Tuple(Value, Label)));
const OptionsGroups = Dict(Options);
const NotSelected = "";
export class SelectView extends InputWidgetView {
    static __name__ = "SelectView";
    connect_signals() {
        super.connect_signals();
        const { value, options } = this.model.properties;
        this.on_change(value, () => {
            this._update_value();
        });
        this.on_change(options, () => {
            empty(this.input_el);
            this.input_el.append(...this.options_el());
            this._update_value();
        });
    }
    _known_values = new Map();
    options_el() {
        const { _known_values } = this;
        _known_values.clear();
        function build_options(values) {
            return values.map((el) => {
                let value, label;
                if (isString(el)) {
                    value = label = el;
                }
                else {
                    [value, label] = el;
                }
                _known_values.set(value, label);
                return option({ value: label }, label);
            });
        }
        const { options } = this.model;
        if (isArray(options)) {
            return build_options(options);
        }
        else {
            return entries(options).map(([label, values]) => optgroup({ label }, build_options(values)));
        }
    }
    _render_input() {
        this.input_el = select({
            class: inputs.input,
            name: this.model.name,
            disabled: this.model.disabled,
        }, this.options_el());
        this.input_el.addEventListener("change", () => this.change_input());
        return this.input_el;
    }
    render() {
        super.render();
        this._update_value();
    }
    change_input() {
        const selected_label = this.input_el.value;
        const found = [...this._known_values].find(([_, label]) => selected_label == label);
        const value = (() => {
            if (found == null) {
                return NotSelected;
            }
            else {
                const [value, _] = found;
                return value;
            }
        })();
        this.model.value = value;
        super.change_input();
    }
    _update_value() {
        const { value } = this.model;
        const label = this._known_values.get(value);
        if (label !== undefined) {
            this.input_el.value = label;
        }
        else {
            this.input_el.removeAttribute("value");
            this.input_el.selectedIndex = -1;
        }
    }
}
export class Select extends InputWidget {
    static __name__ = "Select";
    constructor(attrs) {
        super(attrs);
    }
    static {
        this.prototype.default_view = SelectView;
        this.define(() => {
            return {
                value: [Value, NotSelected],
                options: [Or(Options, OptionsGroups), []],
            };
        });
    }
}
//# sourceMappingURL=select.js.map