import { focus } from '@dojo/framework/core/middleware/focus';
import { i18n } from '@dojo/framework/core/middleware/i18n';
import { createICacheMiddleware } from '@dojo/framework/core/middleware/icache';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
import { uuid } from '@dojo/framework/core/util';
import { create, tsx } from '@dojo/framework/core/vdom';
import { Keys } from '../common/util';
import HelperText from '../helper-text';
import Icon from '../icon';
import Label from '../label';
import { List } from '../list';
import theme from '../middleware/theme';
import TriggerPopup from '../trigger-popup';
import * as listCss from '../theme/default/list.m.css';
import * as labelCss from '../theme/default/label.m.css';
import * as iconCss from '../theme/default/icon.m.css';
import * as css from '../theme/default/select.m.css';
import bundle from './nls/Select';
import LoadingIndicator from '../loading-indicator';
import { find } from '@dojo/framework/shim/array';
const icache = createICacheMiddleware();
const factory = create({
    icache,
    focus,
    theme,
    i18n,
    resource: createResourceMiddleware()
})
    .properties()
    .children();
export const Select = factory(function Select({ children, properties, middleware: { icache, focus, theme, i18n, resource } }) {
    const { classes, variant, theme: themeProp, disabled, helperText, initialValue, itemsInView = 6, onValidate, onValue, placeholder = '', position, required, name, resource: { template, options = resource.createOptions((curr, next) => (Object.assign({}, curr, next))) } } = properties();
    const { get, template: { read } } = resource.template(template);
    const [{ items, label } = { items: undefined, label: undefined }] = children();
    let { value } = properties();
    if (value === undefined) {
        if (initialValue !== undefined && initialValue !== icache.get('initial')) {
            icache.set('initial', initialValue);
            icache.set('value', initialValue);
        }
        value = icache.get('value');
    }
    const menuId = icache.getOrSet('menuId', uuid());
    const triggerId = icache.getOrSet('triggerId', uuid());
    const focusNode = icache.getOrSet('focusNode', 'trigger');
    const shouldFocus = focus.shouldFocus();
    const themedCss = theme.classes(css);
    let valid = icache.get('valid');
    const dirty = icache.get('dirty');
    const { messages } = i18n.localize(bundle);
    const expanded = icache.get('expanded');
    const { meta: { total, status }, data } = get(options(), { read, meta: true });
    if (required && (dirty || value !== undefined)) {
        const isValid = value !== undefined;
        if (isValid !== valid) {
            icache.set('valid', isValid);
            valid = isValid;
            onValidate && onValidate(isValid);
        }
    }
    let valueOption;
    if (value && data) {
        let found = find(data, (item) => {
            return Boolean(item.value && item.value.value === value);
        });
        if (found) {
            valueOption = found.value;
        }
        else {
            const items = get(options({ query: { value } }), { read });
            if (items && items.length > 0 && items[0].value === value) {
                valueOption = items[0];
            }
        }
    }
    value = valueOption ? valueOption.value : undefined;
    return (tsx("div", { classes: [
            theme.variant(),
            themedCss.root,
            disabled && themedCss.disabled,
            valid === true && themedCss.valid,
            valid === false && themedCss.invalid,
            shouldFocus === true && themedCss.focused,
            expanded && themedCss.expanded
        ], key: "root" },
        label && (tsx(Label, { theme: theme.compose(labelCss, css, 'label'), classes: classes, variant: variant, disabled: disabled, forId: triggerId, valid: valid, required: required, active: !!(value || icache.get('expanded')), focused: shouldFocus }, label)),
        tsx(TriggerPopup, { key: "popup", onOpen: () => {
                icache.set('expanded', true);
            }, onClose: () => {
                icache.set('expanded', false);
                if (!dirty) {
                    icache.set('dirty', true);
                }
            }, position: position, theme: themeProp, classes: classes, variant: variant }, {
            trigger: (toggleOpen) => {
                function openMenu() {
                    if (!disabled) {
                        icache.set('focusNode', 'menu');
                        focus.focus();
                        toggleOpen();
                    }
                }
                return (tsx("button", { name: name, value: value, focus: () => focusNode === 'trigger' && shouldFocus, "aria-controls": menuId, "aria-haspopup": "listbox", "aria-expanded": icache.getOrSet('expanded', false) ? 'true' : 'false', key: "trigger", type: "button", id: triggerId, disabled: disabled, classes: themedCss.trigger, onclick: openMenu, onkeydown: (event) => {
                        if (event.which === Keys.Down ||
                            event.which === Keys.Space ||
                            event.which === Keys.Enter) {
                            event.preventDefault();
                            openMenu();
                        }
                    } },
                    tsx("span", { classes: [themedCss.value, expanded && themedCss.valueExpanded] }, (valueOption && valueOption.label) || (tsx("span", { classes: themedCss.placeholder }, placeholder))),
                    tsx("span", { classes: themedCss.arrow },
                        tsx(Icon, { type: "downIcon", theme: theme.compose(iconCss, css, 'icon'), classes: classes, variant: variant }))));
            },
            content: (close) => {
                function closeMenu() {
                    icache.set('focusNode', 'trigger');
                    close();
                }
                return total === undefined && status === 'reading' ? (tsx(LoadingIndicator, { key: "loading", theme: themeProp, variant: variant, classes: classes })) : (tsx("div", { key: "menu-wrapper", classes: themedCss.menuWrapper },
                    tsx(List, { key: "menu", height: "auto", focus: () => focusNode === 'menu' && shouldFocus, resource: resource({ template, options }), onValue: (value) => {
                            focus.focus();
                            closeMenu();
                            value.value !== icache.get('value') &&
                                icache.set('value', value.value);
                            onValue(value);
                        }, onRequestClose: closeMenu, onBlur: closeMenu, initialValue: value, itemsInView: itemsInView, theme: theme.compose(listCss, css, 'menu'), classes: classes, variant: variant, widgetId: menuId }, items)));
            }
        }),
        tsx(HelperText, { key: "helperText", text: valid === false ? messages.requiredMessage : helperText, valid: valid, classes: classes, variant: variant, theme: themeProp })));
});
export default Select;

/*# sourceMappingURL=index.mjs.map*/