"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var focus_1 = require("@dojo/framework/core/middleware/focus");
var dimensions_1 = require("@dojo/framework/core/middleware/dimensions");
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()
    .children();
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();
    }
    var _f = tslib_1.__read(children()), firstChild = _f[0], otherChildren = _f.slice(1);
    var _g = util_1.isRenderResult(firstChild)
        ? { primary: tslib_1.__spread([firstChild], otherChildren) }
        : firstChild, _h = _g.leading, leading = _h === void 0 ? undefined : _h, primary = _g.primary, _j = _g.trailing, trailing = _j === void 0 ? undefined : _j;
    return (vdom_1.tsx("div", { id: widgetId, key: "root", onpointermove: util_2.throttle(function () {
            requestActive();
        }, 500), classes: [
            theme.variant(),
            themedCss.root,
            themedCss.height,
            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 } },
        leading ? vdom_1.tsx("span", { classes: themedCss.leading }, leading) : undefined,
        vdom_1.tsx("span", { classes: themedCss.primary }, primary),
        trailing ? vdom_1.tsx("span", { classes: themedCss.trailing }, trailing) : undefined,
        draggable && !trailing && (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,
    dimensions: dimensions_1.default,
    resource: resources_1.createResourceMiddleware()
})
    .properties()
    .children();
var defaultItemsInView = 10;
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, dimensions = _b.dimensions;
    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 ? defaultItemsInView : _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 ? resource.createOptions(function (curr, next) { return (tslib_1.__assign({}, curr, next)); }) : _h, classes = _c.classes, _j = _c.height, height = _j === void 0 ? 'fixed' : _j;
    var _k = resource.template(template), get = _k.get, read = _k.template.read;
    var themedCss = theme.classes(css);
    var _l = tslib_1.__read(children(), 1), itemRenderer = _l[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 _a = properties(), disabled = _a.disabled, activeIndex = _a.activeIndex;
        event.stopPropagation();
        var computedActiveIndex = activeIndex === undefined ? icache.get('activeIndex') : activeIndex;
        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 {
                    var effectiveActiveIndex = computedActiveIndex !== undefined ? computedActiveIndex + 1 : 0;
                    setActiveIndex(effectiveActiveIndex % total);
                }
                break;
            case util_1.Keys.Up:
                event.preventDefault();
                if (event.metaKey || event.ctrlKey) {
                    setActiveIndex(0);
                }
                else {
                    var effectiveActiveIndex = computedActiveIndex !== undefined
                        ? computedActiveIndex - 1 + total
                        : total - 1;
                    setActiveIndex(effectiveActiveIndex % 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');
                            icache.delete('previousInputText');
                        }, 800);
                    });
                    icache.set('inputText', function (value) {
                        if (value === void 0) { value = ''; }
                        return "" + value + event.key;
                    });
                }
                break;
        }
    }
    function renderItems(start, count) {
        var renderedItems = [];
        var resourceRequestSize = options().size;
        var _a = get(options(), { meta: true, read: read }).meta.total, total = _a === void 0 ? 0 : _a;
        if (total) {
            var pages_1 = [];
            for (var i = 0; i < Math.min(total - start, count); i++) {
                var index = i + startNode;
                var page = Math.floor(index / resourceRequestSize) + 1;
                if (pages_1.indexOf(page) === -1) {
                    pages_1.push(page);
                }
            }
            if (!pages_1.length) {
                pages_1.push(1);
            }
            var pageItems = pages_1.map(function (page, index) {
                if (index === pages_1.length - 1) {
                    options({ offset: (page - 1) * options().size });
                }
                return get(tslib_1.__assign({}, options(), { offset: (page - 1) * options().size }), { read: read });
            });
            for (var i = 0; i < Math.min(total - start, count); i++) {
                var index = i + startNode;
                var page = Math.floor(index / resourceRequestSize) + 1;
                var pageIndex = pages_1.indexOf(page);
                var indexWithinPage = index - (page - 1) * resourceRequestSize;
                var items_1 = pageItems[pageIndex];
                if (items_1 && items_1[indexWithinPage]) {
                    var _b = items_1[indexWithinPage], value = _b.value, label = _b.label, disabled = _b.disabled, divider = _b.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
        };
        var itemHeight = icache.getOrSet('itemHeight', 0);
        return (vdom_1.tsx("div", { key: "item-" + index, styles: { height: itemHeight + "px" } }, 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 _m = properties(), selectedValue = _m.value, draggable = _m.draggable, onMove = _m.onMove;
    if (selectedValue === undefined) {
        if (initialValue !== undefined && initialValue !== icache.get('initial')) {
            icache.set('initial', initialValue);
            icache.set('value', initialValue);
        }
        selectedValue = icache.get('value');
    }
    var calculatedItemsInView = icache.getOrSet('calculatedItemsInView', 0);
    if (itemsInView !== icache.get('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 (vdom_1.tsx("div", { styles: { padding: '0' }, classes: [themedCss.root, fixedCss.root] }, offscreenMenuItem_1)); }, function (node) { return node.getBoundingClientRect().height; }));
        if (itemsInView !== 'fill') {
            calculatedItemsInView = itemsInView;
            itemHeight_1 && icache.set('menuHeight', calculatedItemsInView * itemHeight_1);
        }
        else {
            var dims = dimensions.get('fill-root');
            if (dims.size.height) {
                calculatedItemsInView = Math.ceil(dims.size.height / itemHeight_1);
                itemHeight_1 && icache.set('menuHeight', dims.size.height);
            }
            else if (dims.size.width) {
                calculatedItemsInView = defaultItemsInView;
                itemHeight_1 && icache.set('menuHeight', calculatedItemsInView * itemHeight_1);
            }
            else {
                return vdom_1.tsx("div", { key: "fill-root", styles: { height: '100%' } });
            }
        }
        icache.set('itemsInView', itemsInView);
        icache.set('calculatedItemsInView', calculatedItemsInView);
    }
    var menuHeight = icache.get('menuHeight');
    var idBase = widgetId || "menu-" + id;
    var rootStyles = {};
    if (menuHeight) {
        rootStyles =
            height === 'fixed' ? { height: menuHeight + "px" } : { maxHeight: menuHeight + "px" };
    }
    var shouldFocus = focus.shouldFocus();
    var itemHeight = icache.getOrSet('itemHeight', 0);
    var scrollTop = icache.getOrSet('scrollTop', 0);
    var nodePadding = Math.min(calculatedItemsInView, 20);
    var renderedItemsCount = calculatedItemsInView + 2 * nodePadding;
    var computedActiveIndex = activeIndex === undefined ? icache.get('activeIndex') : activeIndex;
    var inputText = icache.get('inputText');
    var _o = get(options(), { meta: true, read: read }).meta.total, total = _o === void 0 ? 0 : _o;
    if (inputText && inputText !== icache.get('previousInputText') && total) {
        var items_2 = get(tslib_1.__assign({}, options(), { offset: 0, size: total }));
        var first = computedActiveIndex !== undefined ? items_2.slice(0, computedActiveIndex) : items_2;
        var second = computedActiveIndex !== undefined ? items_2.slice(computedActiveIndex) : [];
        var foundIndex = computedActiveIndex;
        if (foundIndex !== undefined) {
            for (var i = 1; i < second.length; i++) {
                var item = second[i];
                if (item && item.label.toLowerCase().indexOf(inputText.toLowerCase()) === 0) {
                    foundIndex = foundIndex + i;
                    break;
                }
            }
        }
        if (foundIndex === computedActiveIndex) {
            for (var i = 0; i < first.length; i++) {
                var item = first[i];
                if (item && item.label.toLowerCase().indexOf(inputText.toLowerCase()) === 0) {
                    foundIndex = i;
                    break;
                }
            }
        }
        if (foundIndex !== undefined && foundIndex !== computedActiveIndex) {
            setActiveIndex(foundIndex);
        }
        icache.set('previousInputText', inputText);
    }
    var previousActiveIndex = icache.get('previousActiveIndex');
    computedActiveIndex = activeIndex === undefined ? icache.get('activeIndex') : activeIndex;
    var activeItem = undefined;
    if (computedActiveIndex !== undefined && computedActiveIndex !== previousActiveIndex) {
        var visibleStartIndex = Math.floor(scrollTop / itemHeight);
        var visibleEndIndex = visibleStartIndex + calculatedItemsInView - 1;
        if (computedActiveIndex < visibleStartIndex) {
            scrollTop = computedActiveIndex * itemHeight;
        }
        else if (computedActiveIndex > visibleEndIndex) {
            scrollTop = Math.max(computedActiveIndex + 1 - calculatedItemsInView, 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);
    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) {
            total && 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": computedActiveIndex !== undefined
            ? idBase + "-item-" + computedActiveIndex
            : undefined, 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*/