import * as i0 from '@angular/core';
import { Component, ViewEncapsulation, Attribute, Inject, Optional, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PROP_STRING, PROP_ANY, PROP_NUMBER, PROP_BOOLEAN, register, StylableComponent, APPLY_STYLES_TYPE, styler, getOrderedDataset, getEvaluatedData, provideAsWidgetRef, WmComponentsModule } from '@wm/components/base';
import { getClonedObject, $parseEvent } from '@wm/core';
import { isArray, isObject, isString, isEmpty } from 'lodash-es';

const registerProps = () => {
    register('wm-tree', new Map([
        ['class', PROP_STRING],
        ['dataset', { value: 'node1, node2, node3', ...PROP_ANY }],
        ['datavalue', PROP_STRING],
        ['levels', { value: 0, ...PROP_NUMBER }],
        ['name', PROP_STRING],
        ['nodeaction', PROP_STRING],
        ['nodechildren', PROP_STRING],
        ['nodeclick', { value: 'none', ...PROP_STRING }],
        ['nodeicon', PROP_STRING],
        ['nodeid', PROP_STRING],
        ['nodelabel', PROP_STRING],
        ['orderby', PROP_STRING],
        ['show', { value: true, ...PROP_BOOLEAN }],
        ['tabindex', { value: 0, ...PROP_NUMBER }],
        ['treeicons', PROP_STRING]
    ]));
};

const _c0 = ["wmTree", ""];
const WIDGET_INFO = { widgetType: 'wm-tree', hostClass: 'app-tree' };
const defaultTreeIconClass = 'plus-minus';
class TreeComponent extends StylableComponent {
    static { this.initializeProps = registerProps(); }
    constructor(inj, binddatavalue, bindnodelabel, bindnodeicon, bindnodechildren, bindnodeid, explicitContext) {
        super(inj, WIDGET_INFO, explicitContext);
        this.binddatavalue = binddatavalue;
        this.bindnodelabel = bindnodelabel;
        this.bindnodeicon = bindnodeicon;
        this.bindnodechildren = bindnodechildren;
        this.bindnodeid = bindnodeid;
        this.setting = {
            data: {
                simpleData: {
                    enable: false
                }
            },
            view: {
                dblClickExpand: false,
                fontCss: {
                    'font-awesome': true
                },
                switchIcon: {},
            },
            check: {},
            callback: {}
        };
        styler(this.nativeElement, this, APPLY_STYLES_TYPE.CONTAINER);
        this.setting.view['nodeClasses'] = this.setNodeClasses;
        this.setting.callback["onClick"] = this.onClick.bind(this);
        this.setting.callback["onExpand"] = this.onExpand.bind(this);
        this.setting.callback["onCollapse"] = this.onCollapse.bind(this);
    }
    onPropertyChange(key, nv, ov) {
        switch (key) {
            case 'dataset':
                this.nodes = this.getNodes(nv);
                this.renderTree();
                break;
            case 'levels':
                this.level = nv;
                this.renderTree();
                break;
            case 'nodeicon':
                this.nodeicon = nv;
                this.renderTree();
                break;
            case 'nodelabel':
                this.nodelabel = nv;
                this.renderTree();
                break;
            case 'nodechildren':
                this.nodechildren = nv;
                this.renderTree();
                break;
            case 'orderby':
                this.orderby = nv;
                this.renderTree();
                break;
            case 'treeicons':
                this.treeicons = nv;
                this.renderTree();
                break;
            case 'class':
                this.treeClass = nv;
                this.setTreeTemplate(this.treeClass);
                this.renderTree();
            default:
                super.onPropertyChange(key, nv, ov);
                break;
        }
    }
    // expands the tree nodes if the property is selected.
    expandTree(level, node, childLevel) {
        node.map(childNode => {
            const children = childNode.children;
            if (children && childLevel < level) {
                childNode.open = true;
                this.expandTree(level, children, childLevel + 1);
            }
            else {
                childLevel = 0;
                return;
            }
        });
    }
    // sets the template for the tree based on the property selected.
    setTreeTemplate(value) {
        const classList = value.split(" ");
        if (classList.includes('Classic')) {
            this.setting.check["enable"] = false;
        }
        else if (classList.includes('Checkbox')) {
            this.setting.check["enable"] = true;
            this.setting.check["chkStyle"] = 'checkbox';
        }
        else if (classList.includes('Radio')) {
            this.setting.check["enable"] = true;
            this.setting.check["chkStyle"] = 'radio';
            this.setting.check["radioType"] = "all";
        }
    }
    // extracts nodes from string format
    getNodesFromString(value) {
        return value.split(',').map((item) => {
            return {
                'label': item && item.trim()
            };
        });
    }
    // gets the nodes and orders the nodes if required
    getNodes(newVal) {
        let nodes;
        if (isArray(newVal)) {
            nodes = getOrderedDataset(newVal, this.orderby);
        }
        else if (isObject(newVal)) {
            nodes = [newVal];
        }
        else if (isString(newVal) && !isEmpty(newVal)) {
            newVal = newVal.trim();
            if (newVal) {
                nodes = this.getNodesFromString(newVal);
            }
        }
        return nodes;
    }
    // adds class to the nodes inorder to add icons to respective node.
    setNodeClasses(treeId, treeNode) {
        return treeNode.icon ? { add: [`${treeNode.icon}`] } : '';
    }
    ;
    // adds tree icons to the nodes on load of the tree
    changeTreeIcons(nv) {
        let eleClose = $('ul[name="' + this.name + '"] li span.button.switch');
        $(eleClose).map((idx, ele) => {
            $(ele).addClass(nv);
            $(ele).on("click", function (e) {
                setTimeout(() => {
                    $(ele).addClass(nv);
                }, 0);
            });
        });
    }
    // Returns the node path
    getPath(treeNode, path) {
        if (treeNode.getParentNode() === null) {
            path = "/" + treeNode.name + path;
        }
        else {
            path = this.getPath(treeNode.getParentNode(), path) + "/" + treeNode.name;
        }
        return path;
    }
    // binds the click event to all nodes to open the child nodes
    onClick(event, treeId, treeNode, clickFlag) {
        if (this.nodeclick === "expand") {
            var nodes = this.zTree.getSelectedNodes();
            if (nodes.length > 0) {
                this.expandNode(nodes[0], !nodes[0].open, true);
            }
        }
        this.selectNode(event, treeNode);
    }
    // Adds tree icon classes to child nodes when expanded
    onExpand(event, treeId, treeNode) {
        let self = this;
        let path = this.getPath(treeNode, "");
        const eventParams = {
            '$event': event,
            "$item": getClonedObject(treeNode.data),
            "$path": path
        };
        this.invokeEventCallback('expand', eventParams);
        const children = treeNode.children;
        children?.map((el) => {
            if (el.isParent) {
                let ele = $(`#${el.tId}_switch`);
                $(ele).addClass(self.treeicons || defaultTreeIconClass);
                $(ele).on("click", function (e) {
                    setTimeout(() => {
                        $(ele).addClass(self.treeicons || defaultTreeIconClass);
                    }, 0);
                });
            }
        });
    }
    onCollapse(event, treeId, treeNode) {
        let path = this.getPath(treeNode, "");
        const eventParams = {
            '$event': event,
            "$item": getClonedObject(treeNode.data),
            "$path": path
        };
        this.invokeEventCallback('collapse', eventParams);
    }
    // function to support backward compatibility of objects
    constructZTreeData(data, zTreeData) {
        data.forEach(node => {
            const zNode = {};
            const name = getEvaluatedData(node, { field: this.nodelabel, bindExpression: this.bindnodelabel }, this.viewParent) || node.label;
            const icon = getEvaluatedData(node, { field: this.nodeicon, bindExpression: this.bindnodeicon }, this.viewParent) || node.icon;
            const nodeId = getEvaluatedData(node, { field: this.nodeid, bindExpression: this.bindnodeid }, this.viewParent);
            const children = getEvaluatedData(node, { field: this.nodechildren, bindExpression: this.bindnodechildren }, this.viewParent) || node.children;
            zNode['name'] = name;
            zNode['icon'] = icon;
            zNode['nodeId'] = nodeId;
            zNode['data'] = getClonedObject(node);
            if (isArray(children) && children.length) {
                zNode['children'] = [];
                this.constructZTreeData(children, zNode['children']);
            }
            zTreeData.push(zNode);
        });
    }
    // Renders the tree on to the dom
    renderTree() {
        this.zTreeNodes = [];
        if (this.nodes?.length) {
            this.nativeElement.setAttribute('id', this.name);
            this.constructZTreeData(this.nodes, this.zTreeNodes);
            if (this.level > 0) {
                this.expandTree(this.level, this.zTreeNodes, 0);
            }
        }
        this.zTree = $.fn.zTree.init($('ul[name="' + this.name + '"]'), this.setting, this.zTreeNodes);
        $.fn.zTreeKeyboardNavigation(this.zTree, $('ul[name="' + this.name + '"]'), null, this.treeicons || defaultTreeIconClass);
        this.postRenderTree();
    }
    setChecked(zNode, node) {
        node.checked = zNode.checked;
        const children = getEvaluatedData(node, { field: this.nodechildren, bindExpression: this.bindnodechildren }, this.viewParent) || node.children;
        if (children?.length) {
            children.forEach((node, index) => {
                this.setChecked(zNode.children[index], node);
            });
        }
    }
    selectNode(event, node) {
        const deSelectElm = $(`.app-tree[name=${this.name}] li[treenode].selected`);
        deSelectElm.removeClass('selected');
        if (!node) {
            return;
        }
        const selectElm = $(`#${node.tId}:has(.curSelectedNode)`);
        selectElm.addClass('selected');
        const classList = (this.treeClass || "").split(" ");
        if (classList.includes('Checkbox') || classList.includes('Radio')) {
            this.setChecked(node, node.data);
        }
        const path = this.getPath(node, "");
        this.selecteditem = getClonedObject(node.data) || {};
        this.selecteditem.path = path;
        const eventParams = {
            '$event': event,
            "$item": getClonedObject(node.data),
            "$path": path
        };
        //[Todo-CSP]: this data will be dynamic, can not generate function upfront
        const nodeAction = node.data[this.nodeaction || 'action'];
        if (nodeAction) {
            $parseEvent(nodeAction)(this);
        }
        this.invokeEventCallback('select', eventParams);
    }
    expandNode(node, expand, eventFlag) {
        this.zTree.expandNode(node, expand, false, false, eventFlag);
        const el = $(`#${node.tId}_switch`);
        $(el).addClass(this.treeicons || defaultTreeIconClass);
    }
    postRenderTree() {
        setTimeout(() => {
            this.changeTreeIcons(this.treeicons || defaultTreeIconClass);
            if (this.datavalue && !this.selecteditem) {
                const nodes = this.zTree.getNodes();
                let node;
                if (nodes.length) {
                    if (this.datavalue === 'FirstNode') {
                        node = nodes[0];
                    }
                    if (this.datavalue === 'LastNode') {
                        node = nodes[nodes.length - 1];
                    }
                }
                if (node) {
                    this.zTree.selectNode(node, false);
                    this.selectNode(undefined, node);
                    this.expandNode(node, true, false);
                }
            }
        }, 200);
    }
    selectById(value) {
        const simpleNodes = this.zTree?.transformToArray(this.zTree.getNodes());
        const node = simpleNodes?.find(node => value === node.nodeId);
        if (node) {
            this.zTree.selectNode(node, false);
            this.selectNode(undefined, node);
        }
    }
    deselectById(value) {
        this.selecteditem = {};
        this.selectById();
    }
    static { this.ɵfac = function TreeComponent_Factory(t) { return new (t || TreeComponent)(i0.ɵɵdirectiveInject(i0.Injector), i0.ɵɵinjectAttribute('datavalue.bind'), i0.ɵɵinjectAttribute('nodelabel.bind'), i0.ɵɵinjectAttribute('nodeicon.bind'), i0.ɵɵinjectAttribute('nodechildren.bind'), i0.ɵɵinjectAttribute('nodeid.bind'), i0.ɵɵdirectiveInject('EXPLICIT_CONTEXT', 8)); }; }
    static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TreeComponent, selectors: [["ul", "wmTree", ""]], features: [i0.ɵɵProvidersFeature([
                provideAsWidgetRef(TreeComponent)
            ]), i0.ɵɵInheritDefinitionFeature], attrs: _c0, decls: 2, vars: 0, consts: [["wmTree", ""], ["id", "ztree", 1, "ztree"]], template: function TreeComponent_Template(rf, ctx) { if (rf & 1) {
            i0.ɵɵelement(0, "ul", 1, 0);
        } }, encapsulation: 2 }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TreeComponent, [{
        type: Component,
        args: [{ selector: 'ul[wmTree]', providers: [
                    provideAsWidgetRef(TreeComponent)
                ], encapsulation: ViewEncapsulation.None, template: "<ul #wmTree class=\"ztree\" id=\"ztree\"></ul>  " }]
    }], () => [{ type: i0.Injector }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['datavalue.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['nodelabel.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['nodeicon.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['nodechildren.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['nodeid.bind']
            }] }, { type: undefined, decorators: [{
                type: Inject,
                args: ['EXPLICIT_CONTEXT']
            }, {
                type: Optional
            }] }], null); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TreeComponent, { className: "TreeComponent", filePath: "tree.component.ts", lineNumber: 20 }); })();

const components = [
    TreeComponent
];
class TreeModule {
    static { this.ɵfac = function TreeModule_Factory(t) { return new (t || TreeModule)(); }; }
    static { this.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: TreeModule }); }
    static { this.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
            WmComponentsModule] }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TreeModule, [{
        type: NgModule,
        args: [{
                imports: [
                    CommonModule,
                    WmComponentsModule
                ],
                declarations: [...components],
                exports: [...components]
            }]
    }], null, null); })();
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(TreeModule, { declarations: [TreeComponent], imports: [CommonModule,
        WmComponentsModule], exports: [TreeComponent] }); })();

/**
 * Generated bundle index. Do not edit.
 */

export { TreeComponent, TreeModule };
//# sourceMappingURL=index.mjs.map
