"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var vdom_1 = require("@dojo/framework/core/vdom");
var icache_1 = require("@dojo/framework/core/middleware/icache");
var resources_1 = require("@dojo/framework/core/middleware/resources");
var theme_1 = require("../middleware/theme");
var focus_1 = require("@dojo/framework/core/middleware/focus");
var array_1 = require("@dojo/framework/shim/array");
var util_1 = require("../common/util");
var icon_1 = require("../icon");
var checkbox_1 = require("../checkbox");
var list_1 = require("../list");
var css = require("../theme/default/tree.m.css");
var loading_indicator_1 = require("../loading-indicator");
var resource = resources_1.createResourceMiddleware();
var icache = icache_1.createICacheMiddleware();
var factory = vdom_1.create({ theme: theme_1.default, icache: icache, diffProperty: vdom_1.diffProperty, focus: focus_1.default, resource: resource })
    .properties()
    .children();
exports.default = factory(function Tree(_a) {
    var _b = _a.middleware, theme = _b.theme, icache = _b.icache, diffProperty = _b.diffProperty, resource = _b.resource, properties = _a.properties, children = _a.children;
    diffProperty('value', properties, function (_a, _b) {
        var current = _a.value;
        var next = _b.value;
        if ((current || next) && current !== next) {
            icache.set('value', next);
        }
    });
    diffProperty('initialChecked', properties, function (_a, _b) {
        var current = _a.initialChecked;
        var next = _b.initialChecked;
        if ((current || next) && current !== next) {
            icache.set('checkedIds', next || []);
        }
    });
    diffProperty('initialExpanded', properties, function (_a, _b) {
        var current = _a.initialExpanded;
        var next = _b.initialExpanded;
        if ((current || next) && current !== next) {
            icache.set('expandedIds', next || []);
        }
    });
    var _c = properties(), _d = _c.checkable, checkable = _d === void 0 ? false : _d, _e = _c.selectable, selectable = _e === void 0 ? false : _e, checkedIds = _c.checkedIds, expandedIds = _c.expandedIds, onValue = _c.onValue, onCheck = _c.onCheck, onExpand = _c.onExpand, disabledIds = _c.disabledIds, template = _c.resource.template, _f = _c.parentSelection, parentSelection = _f === void 0 ? false : _f, themeProp = _c.theme, classes = _c.classes, variant = _c.variant;
    var _g = resource.template(template), get = _g.get, read = _g.template.read;
    var themedCss = theme.classes(css);
    var defaultRenderer = function (n) { return n.value; };
    var _h = tslib_1.__read(children(), 1), itemRenderer = _h[0];
    var activeNode = icache.get('activeNode');
    var selectedNode = icache.get('value');
    if (checkedIds) {
        icache.set('checkedIds', checkedIds);
    }
    if (expandedIds) {
        icache.set('expandedIds', expandedIds);
    }
    var expandedNodes = icache.getOrSet('expandedIds', []);
    var checkedNodes = icache.getOrSet('checkedIds', []);
    function activateNode(id) {
        icache.set('activeNode', id);
    }
    function selectNode(id) {
        icache.set('value', id);
        onValue && onValue(id);
    }
    function checkNode(id, checked) {
        if (checked) {
            icache.set('checkedIds', function (currentChecked) {
                if (currentChecked === void 0) { currentChecked = []; }
                return tslib_1.__spread(currentChecked, [id]);
            });
        }
        else {
            icache.set('checkedIds', function (currentChecked) {
                if (currentChecked === void 0) { currentChecked = []; }
                return currentChecked ? currentChecked.filter(function (n) { return n !== id; }) : [];
            });
        }
        onCheck && onCheck(icache.get('checkedIds') || []);
    }
    function expandNode(id) {
        icache.set('expandedIds', function (currentExpanded) {
            if (currentExpanded === void 0) { currentExpanded = []; }
            return tslib_1.__spread(currentExpanded, [id]);
        });
        onExpand && onExpand(icache.get('expandedIds') || []);
    }
    function collapseNode(id) {
        icache.set('expandedIds', function (currentExpanded) {
            if (currentExpanded === void 0) { currentExpanded = []; }
            return currentExpanded ? currentExpanded.filter(function (n) { return n !== id; }) : [];
        });
        onExpand && onExpand(icache.get('expandedIds') || []);
    }
    function createNodeFlatMap(nodeId) {
        if (nodeId === void 0) { nodeId = 'root'; }
        var nodes = [];
        var options = resource.createOptions(function (curr, next) { return (tslib_1.__assign({}, curr, next)); });
        var total = get(options({ query: { parent: nodeId } }), { read: read, meta: true }).meta.total;
        if (total) {
            var results = get(options({ size: total }), { read: read });
            var queriedNodes = results ? array_1.flat(results) : [];
            queriedNodes.forEach(function (node) {
                nodes.push(node);
                if (expandedNodes.indexOf(node.id) !== -1) {
                    nodes = tslib_1.__spread(nodes, createNodeFlatMap(node.id));
                }
            });
        }
        return nodes;
    }
    function onKeyDown(event) {
        event.stopPropagation();
        var nodes = createNodeFlatMap();
        var activeIndex = nodes.findIndex(function (node) { return node.id === activeNode; });
        switch (event.which) {
            // select
            case util_1.Keys.Enter:
            case util_1.Keys.Space:
                event.preventDefault();
                if (activeNode && selectedNode !== activeNode && !nodes[activeIndex].hasChildren) {
                    selectable && selectNode(activeNode);
                    checkable && checkNode(activeNode, !checkedNodes.includes(activeNode));
                }
                break;
            // next
            case util_1.Keys.Down:
                event.preventDefault();
                activateNode(nodes[(activeIndex + 1) % nodes.length].id);
                break;
            // previous
            case util_1.Keys.Up:
                event.preventDefault();
                if (activeIndex - 1 < 0) {
                    activateNode(nodes[nodes.length - 1].id);
                }
                else {
                    activateNode(nodes[activeIndex - 1].id);
                }
                break;
            // expand
            case util_1.Keys.Right:
                event.preventDefault();
                if (activeNode &&
                    !expandedNodes.includes(activeNode) &&
                    nodes[activeIndex].hasChildren) {
                    expandNode(activeNode);
                }
                break;
            // collapse
            case util_1.Keys.Left:
                event.preventDefault();
                if (activeNode && expandedNodes.includes(activeNode)) {
                    collapseNode(activeNode);
                }
                break;
        }
    }
    function mapNodeTree(nodeId) {
        if (nodeId === void 0) { nodeId = 'root'; }
        var meta = get({ size: 30, offset: 0, query: { parent: nodeId } }, { read: read, meta: true }).meta;
        if (meta.status !== 'read') {
            return vdom_1.tsx(loading_indicator_1.default, { theme: themeProp, classes: classes, variant: variant });
        }
        var results = get({
            size: meta.total || 0,
            offset: 0,
            query: { parent: nodeId }
        }, { read: read });
        var nodes = results ? array_1.flat(results) : [];
        return (vdom_1.tsx("ol", { classes: [
                nodeId === 'root' ? themedCss.root : null,
                themedCss.nodeParent,
                theme.variant()
            ], onkeydown: onKeyDown, tabIndex: 0, role: nodeId === 'root' ? 'tree' : 'group' }, nodes.map(function (node) {
            var isExpanded = expandedNodes.includes(node.id);
            return (vdom_1.tsx("li", { classes: [
                    themedCss.node,
                    node.hasChildren && themedCss.leaf,
                    selectable && themedCss.selectable,
                    node.id === selectedNode && themedCss.selected
                ], role: 'treeitem' },
                vdom_1.tsx(exports.TreeNode, { classes: classes, theme: themeProp, variant: variant, activeNode: activeNode, checkable: checkable, selectable: selectable, selected: node.id === selectedNode, checked: checkedNodes.includes(node.id), value: selectedNode, disabled: (disabledIds || []).includes(node.id), expanded: isExpanded, parentSelection: parentSelection, node: node, onActive: function () { return activateNode(node.id); }, onValue: function () { return selectNode(node.id); }, onCheck: function (checked) { return checkNode(node.id, checked); }, onExpand: function (expanded) {
                        if (expanded) {
                            expandNode(node.id);
                        }
                        else {
                            collapseNode(node.id);
                        }
                    } }, itemRenderer || defaultRenderer),
                isExpanded && mapNodeTree(node.id)));
        })));
    }
    return mapNodeTree();
});
var treeNodeFactory = vdom_1.create({ theme: theme_1.default })
    .properties()
    .children();
exports.TreeNode = treeNodeFactory(function TreeNode(_a) {
    var theme = _a.middleware.theme, properties = _a.properties, children = _a.children;
    var _b = properties(), node = _b.node, checkable = _b.checkable, selectable = _b.selectable, activeNode = _b.activeNode, checked = _b.checked, disabled = _b.disabled, expanded = _b.expanded, selected = _b.selected, onActive = _b.onActive, onValue = _b.onValue, onCheck = _b.onCheck, onExpand = _b.onExpand, parentSelection = _b.parentSelection, themeProp = _b.theme, classes = _b.classes, variant = _b.variant;
    var _c = tslib_1.__read(children(), 1), itemRenderer = _c[0];
    var themedCss = theme.classes(css);
    var isActive = node.id === activeNode;
    var isExpandable = node.hasChildren;
    return (vdom_1.tsx(list_1.ListItem, { active: isActive, selected: selected, onRequestActive: function () {
            onActive();
        }, onSelect: function () {
            isExpandable && onExpand(!expanded);
            if (parentSelection || !isExpandable) {
                selectable && onValue();
                checkable && onCheck(!checked);
            }
        }, disabled: disabled, widgetId: node.id, classes: classes, theme: themeProp, variant: variant },
        vdom_1.tsx("div", { classes: themedCss.contentWrapper },
            vdom_1.tsx("div", { classes: themedCss.content },
                isExpandable && (vdom_1.tsx("div", { classes: themedCss.expander },
                    vdom_1.tsx(icon_1.default, { type: expanded ? 'downIcon' : 'rightIcon', theme: themeProp, classes: classes, variant: variant }))),
                checkable && (parentSelection || !isExpandable) && (vdom_1.tsx("div", { onpointerdown: function (event) {
                        // don't allow the check's activity to effect our expand/collapse
                        event.stopPropagation();
                    } },
                    vdom_1.tsx(checkbox_1.default, { checked: !!checked, onValue: function (value) {
                            onCheck(value);
                        }, disabled: disabled, classes: classes, theme: themeProp, variant: variant }))),
                vdom_1.tsx("div", { classes: themedCss.title }, itemRenderer(node))))));
});

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