"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var focus_1 = require("@dojo/framework/core/middleware/focus");
var icache_1 = require("@dojo/framework/core/middleware/icache");
var vdom_1 = require("@dojo/framework/core/vdom");
var util_1 = require("../common/util");
var theme_1 = require("../middleware/theme");
var offscreen_1 = require("../middleware/offscreen");
var listItemCss = require("../theme/default/list-item.m.css");
var menuItemCss = require("../theme/default/menu-item.m.css");
var css = require("../theme/default/list.m.css");
var fixedCss = require("./list.m.css");
var resources_1 = require("@dojo/framework/core/middleware/resources");
var loading_indicator_1 = require("../loading-indicator");
var util_2 = require("@dojo/framework/core/util");
var icon_1 = require("../icon");
var menuItemFactory = vdom_1.create({ theme: theme_1.default }).properties();
exports.MenuItem = menuItemFactory(function MenuItem(_a) {
    var properties = _a.properties, children = _a.children, theme = _a.middleware.theme;
    var _b = properties(), onSelect = _b.onSelect, _c = _b.active, active = _c === void 0 ? false : _c, onRequestActive = _b.onRequestActive, _d = _b.disabled, disabled = _d === void 0 ? false : _d, widgetId = _b.widgetId;
    var themedCss = theme.classes(menuItemCss);
    function select() {
        !disabled && onSelect();
    }
    function requestActive() {
        !disabled && !active && onRequestActive();
    }
    return (vdom_1.tsx("div", { id: widgetId, key: "root", onpointermove: util_2.throttle(function () {
            requestActive();
        }, 500), classes: [
            theme.variant(),
            themedCss.root,
            active && themedCss.active,
            disabled && themedCss.disabled
        ], onclick: function () {
            requestActive();
            select();
        }, role: "menuitem", "aria-disabled": disabled ? 'true' : 'false' }, children()));
});
var listItemFactory = vdom_1.create({ theme: theme_1.default }).properties();
exports.ListItem = listItemFactory(function ListItem(_a) {
    var properties = _a.properties, children = _a.children, theme = _a.middleware.theme;
    var _b = properties(), onSelect = _b.onSelect, _c = _b.active, active = _c === void 0 ? false : _c, onRequestActive = _b.onRequestActive, _d = _b.selected, selected = _d === void 0 ? false : _d, _e = _b.disabled, disabled = _e === void 0 ? false : _e, widgetId = _b.widgetId, draggable = _b.draggable, dragged = _b.dragged, onDragStart = _b.onDragStart, onDragEnd = _b.onDragEnd, onDragOver = _b.onDragOver, onDrop = _b.onDrop, movedUp = _b.movedUp, movedDown = _b.movedDown, collapsed = _b.collapsed, themeProp = _b.theme, variant = _b.variant;
    var themedCss = theme.classes(listItemCss);
    function select() {
        !disabled && onSelect();
    }
    function requestActive() {
        !disabled && !active && onRequestActive();
    }
    return (vdom_1.tsx("div", { id: widgetId, key: "root", onpointermove: util_2.throttle(function () {
            requestActive();
        }, 500), classes: [
            theme.variant(),
            themedCss.root,
            selected && themedCss.selected,
            active && themedCss.active,
            disabled && themedCss.disabled,
            movedUp && themedCss.movedUp,
            movedDown && themedCss.movedDown,
            collapsed && themedCss.collapsed,
            dragged && themedCss.dragged,
            draggable && themedCss.draggable
        ], onclick: function () {
            requestActive();
            select();
        }, role: "option", "aria-disabled": disabled ? 'true' : 'false', "aria-selected": selected ? 'true' : 'false', draggable: draggable, ondragenter: function (event) { return event.preventDefault(); }, ondragstart: onDragStart, ondragend: onDragEnd, ondragover: onDragOver, ondrop: onDrop, styles: { visibility: dragged ? 'hidden' : undefined } },
        children(),
        draggable && (vdom_1.tsx(icon_1.default, { type: "barsIcon", classes: { '@dojo/widgets/icon': { icon: [themedCss.dragIcon] } }, theme: themeProp, variant: variant }))));
});
var factory = vdom_1.create({
    icache: icache_1.createICacheMiddleware(),
    focus: focus_1.focus,
    theme: theme_1.default,
    offscreen: offscreen_1.default,
    resource: resources_1.createResourceMiddleware()
})
    .properties()
    .children();
exports.List = factory(function List(_a) {
    var children = _a.children, properties = _a.properties, id = _a.id, _b = _a.middleware, icache = _b.icache, focus = _b.focus, theme = _b.theme, resource = _b.resource, offscreen = _b.offscreen;
    var getOrRead = resource.getOrRead, createOptions = resource.createOptions, find = resource.find, meta = resource.meta, isLoading = resource.isLoading;
    var _c = properties(), activeIndex = _c.activeIndex, _d = _c.focusable, focusable = _d === void 0 ? true : _d, initialValue = _c.initialValue, _e = _c.itemsInView, itemsInView = _e === void 0 ? 10 : _e, _f = _c.menu, menu = _f === void 0 ? false : _f, onActiveIndexChange = _c.onActiveIndexChange, onBlur = _c.onBlur, onFocus = _c.onFocus, onRequestClose = _c.onRequestClose, onValue = _c.onValue, widgetId = _c.widgetId, themeProp = _c.theme, variant = _c.variant, _g = _c.resource, template = _g.template, _h = _g.options, options = _h === void 0 ? createOptions(id) : _h, classes = _c.classes;
    var _j = tslib_1.__read(children(), 1), itemRenderer = _j[0];
    function setActiveIndex(index) {
        if (onActiveIndexChange) {
            onActiveIndexChange(index);
        }
        else {
            icache.set('activeIndex', index);
        }
    }
    function setValue(value) {
        icache.set('value', value.value);
        onValue(value);
    }
    function onKeyDown(event, total) {
        var disabled = properties().disabled;
        event.stopPropagation();
        switch (event.which) {
            case util_1.Keys.Enter:
            case util_1.Keys.Space:
                event.preventDefault();
                if (activeItem) {
                    var itemDisabled = disabled ? disabled(activeItem) : activeItem.disabled;
                    if (!itemDisabled) {
                        setValue(activeItem);
                    }
                }
                break;
            case util_1.Keys.Down:
                event.preventDefault();
                if (event.metaKey || event.ctrlKey) {
                    setActiveIndex(total - 1);
                }
                else {
                    setActiveIndex((computedActiveIndex + 1) % total);
                }
                break;
            case util_1.Keys.Up:
                event.preventDefault();
                if (event.metaKey || event.ctrlKey) {
                    setActiveIndex(0);
                }
                else {
                    setActiveIndex((computedActiveIndex - 1 + total) % total);
                }
                break;
            case util_1.Keys.Escape:
                event.preventDefault();
                onRequestClose && onRequestClose();
                break;
            case util_1.Keys.Home:
                event.preventDefault();
                setActiveIndex(0);
                break;
            case util_1.Keys.End:
                event.preventDefault();
                setActiveIndex(total - 1);
                break;
            default:
                if (!event.metaKey && !event.ctrlKey && event.key.length === 1) {
                    icache.set('resetInputTextTimer', function (existingTimer) {
                        if (existingTimer) {
                            clearTimeout(existingTimer);
                        }
                        return setTimeout(function () {
                            icache.delete('inputText');
                        }, 800);
                    });
                    icache.set('inputText', function (value) {
                        if (value === void 0) { value = ''; }
                        return "" + value + event.key;
                    });
                }
                break;
        }
    }
    function renderItems(start, count, startNode) {
        var renderedItems = [];
        var resourceRequestSize = options().size;
        var metaInfo = meta(template, options(), true);
        if (metaInfo && metaInfo.total) {
            var pages = [];
            for (var i = 0; i < Math.min(metaInfo.total - start, count); i++) {
                var index = i + startNode;
                var page = Math.floor(index / resourceRequestSize) + 1;
                if (pages.indexOf(page) === -1) {
                    pages.push(page);
                }
            }
            if (!pages.length) {
                pages.push(1);
            }
            var pageItems = getOrRead(template, options({ page: pages }));
            for (var i = 0; i < Math.min(metaInfo.total - start, count); i++) {
                var index = i + startNode;
                var page = Math.floor(index / resourceRequestSize) + 1;
                var pageIndex = pages.indexOf(page);
                var indexWithinPage = index - (page - 1) * resourceRequestSize;
                var items_1 = pageItems[pageIndex];
                if (items_1 && items_1[indexWithinPage]) {
                    var _a = items_1[indexWithinPage], value = _a.value, label = _a.label, disabled = _a.disabled, divider = _a.divider;
                    renderedItems[i] = renderItem({ value: value, label: label, disabled: disabled, divider: divider }, index);
                }
                else if (!items_1) {
                    renderedItems[i] = renderPlaceholder(index);
                }
            }
        }
        return renderedItems;
    }
    function renderPlaceholder(index) {
        var itemProps = {
            widgetId: idBase + "-item-" + index,
            key: "item-" + index,
            onSelect: function () { },
            active: false,
            onRequestActive: function () {
                setActiveIndex(index);
            },
            disabled: true,
            classes: classes,
            variant: variant
        };
        return menu ? (vdom_1.tsx(exports.MenuItem, tslib_1.__assign({}, itemProps, { theme: theme.compose(menuItemCss, css, 'item') }),
            vdom_1.tsx(loading_indicator_1.default, null))) : (vdom_1.tsx(exports.ListItem, tslib_1.__assign({}, itemProps, { selected: false, theme: theme.compose(listItemCss, css, 'item'), dragged: icache.get('dragIndex') === index, draggable: draggable, onDragStart: function (event) { return onDragStart(event, index); }, onDragEnd: onDragEnd, onDragOver: function (event) { return onDragOver(event, index); }, onDrop: function (event) { return onDrop(event, index); }, movedUp: icache.get('dragOverIndex') === index &&
                icache.get('dragIndex') < icache.get('dragOverIndex'), movedDown: icache.get('dragOverIndex') === index &&
                icache.get('dragIndex') > icache.get('dragOverIndex'), collapsed: icache.get('dragIndex') === index && icache.get('dragOverIndex') !== undefined }),
            vdom_1.tsx(loading_indicator_1.default, null)));
    }
    function onDragStart(event, index) {
        if (!draggable) {
            return;
        }
        icache.set('dragIndex', index);
        event.dataTransfer.setData('text/plain', "" + index);
    }
    function onDragOver(event, index) {
        var dragIndex = icache.get('dragIndex');
        if (!draggable || dragIndex === undefined) {
            return;
        }
        event.preventDefault();
        event.dataTransfer.dropEffect = 'move';
        var targetIndex = index;
        if (event.offsetY < 10 && index === dragIndex + 1) {
            targetIndex = undefined;
        }
        else if (event.offsetY > itemHeight - 10 && index === dragIndex - 1) {
            targetIndex = undefined;
        }
        if (icache.get('dragOverIndex') !== targetIndex) {
            icache.set('dragOverIndex', targetIndex);
        }
    }
    function onDragEnd(event) {
        if (!draggable) {
            return;
        }
        event.preventDefault();
        icache.set('dragIndex', undefined);
        icache.set('dragOverIndex', undefined);
    }
    function onDrop(event, index) {
        if (!draggable) {
            return;
        }
        event.preventDefault();
        var from = event.dataTransfer && event.dataTransfer.getData('text/plain');
        if (from === null) {
            return;
        }
        setActiveIndex(index);
        onMove && onMove(parseInt(from, 10), index);
    }
    function renderItem(data, index) {
        var disabled = properties().disabled;
        var value = data.value, label = data.label, divider = data.divider, _a = data.disabled, optionDisabled = _a === void 0 ? false : _a;
        var itemDisabled = disabled ? disabled(data) : optionDisabled;
        var selected = value === selectedValue;
        var active = index === computedActiveIndex;
        if (active) {
            activeItem = data;
        }
        var itemProps = {
            widgetId: idBase + "-item-" + index,
            key: "item-" + index,
            onSelect: function () {
                setValue(data);
            },
            active: active,
            onRequestActive: function () {
                setActiveIndex(index);
            },
            disabled: itemDisabled,
            classes: classes,
            variant: variant
        };
        var item;
        if (itemRenderer) {
            item = itemRenderer({
                value: value,
                label: label,
                disabled: itemDisabled,
                active: active,
                selected: selected
            }, tslib_1.__assign({}, itemProps, { theme: themeProp }));
        }
        else {
            var children_1 = label || value;
            item = menu ? (vdom_1.tsx(exports.MenuItem, tslib_1.__assign({}, itemProps, { theme: theme.compose(menuItemCss, css, 'item') }), children_1)) : (vdom_1.tsx(exports.ListItem, tslib_1.__assign({}, itemProps, { theme: theme.compose(listItemCss, css, 'item'), selected: selected, dragged: icache.get('dragIndex') === index, draggable: draggable, onDragStart: function (event) { return onDragStart(event, index); }, onDragEnd: onDragEnd, onDragOver: function (event) { return onDragOver(event, index); }, onDrop: function (event) { return onDrop(event, index); }, movedUp: icache.get('dragOverIndex') === index &&
                    icache.get('dragIndex') < icache.get('dragOverIndex'), movedDown: icache.get('dragOverIndex') === index &&
                    icache.get('dragIndex') > icache.get('dragOverIndex'), collapsed: icache.get('dragIndex') === index &&
                    icache.get('dragOverIndex') !== undefined }), children_1));
        }
        return divider ? [item, vdom_1.tsx("hr", { classes: themedCss.divider })] : item;
    }
    var _k = properties(), selectedValue = _k.value, draggable = _k.draggable, onMove = _k.onMove;
    if (selectedValue === undefined) {
        if (initialValue !== undefined && initialValue !== icache.get('initial')) {
            icache.set('initial', initialValue);
            icache.set('value', initialValue);
        }
        selectedValue = icache.get('value');
    }
    if (itemsInView !== icache.get('itemsInView')) {
        icache.set('itemsInView', itemsInView);
        var offscreenItemProps = {
            selected: false,
            onSelect: function () { },
            active: false,
            onRequestActive: function () { },
            onActive: function () { },
            scrollIntoView: false,
            widgetId: 'offcreen',
            theme: themeProp
        };
        var offscreenMenuItem_1 = itemRenderer ? (itemRenderer({
            selected: false,
            active: false,
            value: 'offscreen',
            label: 'offscreen',
            disabled: false
        }, offscreenItemProps)) : menu ? (vdom_1.tsx(exports.MenuItem, tslib_1.__assign({}, offscreenItemProps), "offscreen")) : (vdom_1.tsx(exports.ListItem, tslib_1.__assign({}, offscreenItemProps), "offscreen"));
        var itemHeight_1 = icache.getOrSet('itemHeight', offscreen(function () { return offscreenMenuItem_1; }, function (node) { return node.getBoundingClientRect().height; }));
        itemHeight_1 && icache.set('menuHeight', itemsInView * itemHeight_1);
    }
    var menuHeight = icache.get('menuHeight');
    var idBase = widgetId || "menu-" + id;
    var rootStyles = menuHeight ? { height: menuHeight + "px" } : {};
    var shouldFocus = focus.shouldFocus();
    var themedCss = theme.classes(css);
    var itemHeight = icache.getOrSet('itemHeight', 0);
    var scrollTop = icache.getOrSet('scrollTop', 0);
    var nodePadding = Math.min(itemsInView, 20);
    var renderedItemsCount = itemsInView + 2 * nodePadding;
    var computedActiveIndex = activeIndex === undefined ? icache.getOrSet('activeIndex', 0) : activeIndex;
    var inputText = icache.get('inputText');
    var requestedInputText = icache.get('requestedInputText');
    if (inputText || requestedInputText) {
        var findOptions = {
            options: options(),
            start: computedActiveIndex + 1,
            type: 'start',
            query: { label: inputText || requestedInputText }
        };
        if (!isLoading(template, findOptions)) {
            var foundItem = find(template, findOptions);
            if (!foundItem) {
                if (inputText && (!requestedInputText || inputText !== requestedInputText)) {
                    icache.set('requestedInputText', inputText);
                }
                else {
                    icache.delete('requestedInputText');
                }
            }
            else {
                icache.delete('requestedInputText');
            }
            if (foundItem && computedActiveIndex !== foundItem.index) {
                setActiveIndex(foundItem.index);
            }
        }
    }
    var previousActiveIndex = icache.get('previousActiveIndex');
    computedActiveIndex =
        activeIndex === undefined ? icache.getOrSet('activeIndex', 0) : activeIndex;
    var activeItem = undefined;
    if (computedActiveIndex !== previousActiveIndex) {
        var visibleStartIndex = Math.floor(scrollTop / itemHeight);
        var visibleEndIndex = visibleStartIndex + itemsInView - 1;
        if (computedActiveIndex < visibleStartIndex) {
            scrollTop = computedActiveIndex * itemHeight;
        }
        else if (computedActiveIndex > visibleEndIndex) {
            scrollTop = Math.max(computedActiveIndex + 1 - itemsInView, 0) * itemHeight;
        }
        if (icache.get('scrollTop') !== scrollTop) {
            icache.set('scrollTop', scrollTop);
        }
        icache.set('previousActiveIndex', computedActiveIndex);
    }
    var startNode = Math.max(0, Math.floor(scrollTop / itemHeight) - nodePadding);
    var offsetY = startNode * itemHeight;
    var items = renderItems(startNode, renderedItemsCount, startNode);
    var metaInfo = meta(template, options(), true);
    var total = metaInfo && metaInfo.total ? metaInfo.total : 0;
    var totalContentHeight = total * itemHeight;
    return (vdom_1.tsx("div", { key: "root", classes: [theme.variant(), themedCss.root, fixedCss.root], tabIndex: focusable ? 0 : -1, onkeydown: function (e) {
            onKeyDown(e, total);
        }, focus: function () { return shouldFocus; }, onfocus: onFocus, onpointerdown: focusable ? undefined : function (event) { return event.preventDefault(); }, onblur: onBlur, scrollTop: scrollTop, onscroll: function (e) {
            var newScrollTop = e.target.scrollTop;
            if (scrollTop !== newScrollTop) {
                icache.set('scrollTop', newScrollTop);
            }
        }, styles: rootStyles, role: menu ? 'menu' : 'listbox', "aria-orientation": "vertical", "aria-activedescendant": idBase + "-item-" + computedActiveIndex, id: idBase },
        vdom_1.tsx("div", { classes: fixedCss.wrapper, styles: {
                height: totalContentHeight + "px"
            }, key: "wrapper" },
            vdom_1.tsx("div", { classes: fixedCss.transformer, styles: {
                    transform: "translateY(" + offsetY + "px)"
                }, key: "transformer" }, items))));
});
exports.default = exports.List;

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