
// https://www.igniteui.com/help/api/2021.2/ui.igtree#events:nodeClick
// https://www.igniteui.com/help/api/2021.1/ui.igtree
//Fired on node click.
//    evt
//Type: Event
//JQuery event object.

//    ui
//Type: Object
//owner
//Type: Object
//Gets a reference to the tree.

//    node
//Type: Object
//Gets a reference to the node object being clicked.

function FilterTreeNodeClicked(evt, ui) {

    var ParentNode = GetParentTreeNode($("#FilterTree"), ui.node);
    var TopLevelNode = GetTopLevelTreeNode($("#FilterTree"), ui.node);

    // Open value poppup
    if (ui.node.data.Text.toLowerCase() == "item name") {
        PopupPromptForValueBox("Item Name", "Enter a name to search for", "", FilterByDatabaseFieldPromptCallback, ui.node/*proceedobject*/);
        return;
    }
    if (ui.node.data.Text.toLowerCase() == "task name") {
        PopupPromptForValueBox("Task name", "Enter value to search for", "", FilterByDatabaseFieldPromptCallback, ui.node/*proceedobject*/);
        return;
    }
    if (ui.node.data.Text.toLowerCase() == "text 1") {
        PopupPromptForValueBox("Text 1", "Enter value to search for", "", FilterByDatabaseFieldPromptCallback, ui.node/*proceedobject*/);
        return;
    }
    if (ui.node.data.Text.toLowerCase() == "text 2") {
        PopupPromptForValueBox("Text 2", "Enter value to search for", "", FilterByDatabaseFieldPromptCallback, ui.node/*proceedobject*/);
        return;
    }
    if (ui.node.data.Text.toLowerCase() == "text 3") {
        PopupPromptForValueBox("Text 3", "Enter value to search for", "", FilterByDatabaseFieldPromptCallback, ui.node/*proceedobject*/);
        return;
    }

    // Normally must have a parent. Don't filter by top-level items
    if (!ParentNode)
        return;
    if (!TopLevelNode)
        return;

    // Don't filter by top-level node
    if (TopLevelNode == ui.node)
        return;

    var FilterNodeText = ui.node.data.Text;
    var FilterNodeValue = ui.node.data.Value;
    var FilterNodeType = ui.node.data.FilterType;
    if (!FilterNodeValue || FilterNodeValue == null || FilterNodeValue == 'undefined')
        FilterNodeValue = ui.node.data.ValueKey;

    // Custom filter type, which is now obsolete since ValueKey contains the type and id
    // Example: 'Projects|~|AD450FF2-54FC-4847-8ED0-EF2F388C37D2'
    if (!FilterNodeType || FilterNodeType == null || FilterNodeType == 'undefined') {
        if (TopLevelNode.data.Value)
             FilterNodeType = TopLevelNode.data.Value;
        else FilterNodeType = TopLevelNode.data.ValueKey;
    }

    // Open custom date range picker (igDialogDateRangePicker)
    if (FilterNodeText.toLowerCase() == "custom date range") {
        DateRangePickerCallback = OnAddCustomDateRangeFilterChoice;
        OpenDateRangePickerDialog();
        return;
    }

    // Open Favorites dialog to filter by selected items
    // Example: Show only favorite projects in timesheet
    if (FilterNodeText.toLowerCase() == "favorites") {
        OpenFavoritesDialog(TopLevelNode.data.Text, TopLevelNode.data.Value);
        return;
    }

    ProcessFilterByRawNodeValues(FilterNodeText, FilterNodeValue, FilterNodeType, ParentNode.data.Text, ParentNode.data.Value, TopLevelNode.data.Text, TopLevelNode.data.Value);

    // Query for subitems under a node
    // Examples:
    //      Subprojects under project
    //      Projects under client
    //      Project tasks under subproject
    AjaxCheckAddTreeNodeSubitems($("#FilterTree"), ui.node, FilterNodeText, FilterNodeValue, FilterNodeType, 1/*nExpandToLevel*/);
}

// Process a filter click
// Find the selected grid pane, and apply filter to it
// Then refresh the selected grid pane
function ProcessFilterByRawNodeValues(FilterNodeText, FilterNodeValue, FilterNodeType, ParentNodeText, ParentNodeValue, TopLevelNodeText, TopLevelNodeValue) {

    var FilterText = FilterNodeText;
    var FilterValue = FilterNodeValue;
    if (!FilterValue)
        FilterValue = FilterText;
    var FilterType = FilterNodeType;
    if (!FilterType)
        FilterType = TopLevelNodeValue;

    ProcessFilter(FilterText, FilterValue, FilterType);
}




// Remember the last time a filter was processed, so tree isn't refreshed
var LastApplyFilterTime = null;

function ProcessFilter(FilterText, FilterValue, FilterType) {

    //console.log("ProcessFilter: " + FilterText + ", " + FilterValue + ", " + FilterType);

    // Get the current FilterJsonString from the selected pane
    // Merge the current filter with the new filter
    // Then refresh the pane with the final filter results
    var CurrentFilterJsonString = GetSelectedContentPaneFilterJsonString();
    var ContentType = GetSelectedContentType();

    if (!bSmallSizeApp) {
        var SelectedContentPane = GetSelectedContentPane();
        if (!SelectedContentPane) {
            ToastError("Filter", "Open a new page to filter its content");
            return;
        }
    }

    // Remember the last time a filter was processed, so tree isn't refreshed
    LastApplyFilterTime = new Date();

    // Apply the filter to the selected content pane
    AjaxApplyFilter(ContentType, CurrentFilterJsonString, FilterText, FilterValue, FilterType);
}



/**
 * Filter the selected content with this new filter value
 * Call Ajax to merge the new filter value with the current value
 * Ajax will return the new filter value
 * The new filter string can then be saved to a cookie for the selected content
 * @param {any} ContentType
 * @param {any} CurrentFilterJsonString
 * @param {any} FilterText
 * @param {any} FilterValue
 * @param {any} FilterType
 */
function AjaxApplyFilter(ContentType, CurrentFilterJsonString, FilterText, FilterValue, FilterType) {

    if (!ContentType)
        return;

    var params = {
        "ContentType": ContentType,
        "CurrentFilterJsonString": CurrentFilterJsonString,
        "FilterText": FilterText,
        "FilterValue": FilterValue,
        "FilterType": FilterType
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetFilterJsonString",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                if (response.CanFilterContent) {
                    //console.log("GetFilterJsonString: " + response.FilterJsonString);

                    // Set the new filter into the selected content
                    SetSelectedContentPaneFilterJsonString(response.FilterJsonString);

                    // Refresh the selected content to show the new filter
                    RefreshSelectedContent();
                }
                else {
                    // "This content cannot be filtered. Select an icon from Home (All Views)."
                    $.toaster({ settings: { timeout: 10000 } });
                    $.toaster(response.FilterMessage, 'Filter', 'danger');
                    $.toaster.reset();
                }
            }
            else {
            }
        },
        error: function (xhr, status, error) {
            var errormsg = "Error " + xhr.status + ", " + xhr.statusText;
            ToastError("AjaxApplyFilter", errormsg);
            console.log('AJAX: ' + errormsg);
        }
    });
}


//Fired after a new node is selected.

//    evt
//Type: Event
//JQuery event object.

//    ui
//Type: Object
//owner
//Type: Object
//Gets a reference to the tree.

//    selectedNodes
//Type: Array
//Gets a reference to currently selected nodes.

//    newNodes
//Type: Array
//Gets a reference to the newly added nodes to the selection.

function FilterTreeNodeSelectionChanged(evt, ui) {
}



// Get the parent of the sepecified tree node
function GetParentTreeNode(treeelement, node) {
    if (!node)
        return null;

    var ParentElement = $(treeelement).igTree("parentNode", node.element);
    if (!ParentElement)
        return null;
    var ParentNode = $(treeelement).igTree("nodeFromElement", ParentElement);
    return ParentNode;
}



// Get the very top-level tree node
function GetTopLevelTreeNode(treeelement, node) {
    if (!node)
        return null;

    var TopLevelNode = node;
    while (true) {
        var ParentElement = $(treeelement).igTree("parentNode", TopLevelNode.element);
        if (!ParentElement)
            return TopLevelNode;

        var ParentNode = $(treeelement).igTree("nodeFromElement", ParentElement);
        if (!ParentNode)
            return TopLevelNode;

        TopLevelNode = ParentNode;
    }
}


// Remove all filtering from the selected content page
function OnRemoveFilter() {

    // Set the new filter into the selected content
    SetSelectedContentPaneFilterJsonString("");

    // Refresh the selected content to show the new filter
    RefreshSelectedContent();
}




/**
 * Filter tree has finished rendering
 * */
function FilterTreeRendered() {

    // Add user-added tree items
    if (!bAddingFilterTreeNodes) {
        setTimeout(function () { AddAllFilterTreeNodesByCookie(); }, 2000);
    }

    // Make tree nodes searchable with a special css style
    // jQuery finds these items and compares their text, then add another class to highlight them

// DOES NOT WORK
// This does not add the class to the correct element, which is actually inside the node 'li' element as an 'href'
    //$(".ui-igtree-node").addClass("searchableitem");

    // Find the tree nodes
    // Each node is an 'li' element
    // Inside each element is an image and some anchor text with href
    // Add the special class to the anchor text element, not these node elements
    var Nodes = $(".ui-igtree-node");
    if (!Nodes)
        return;

    // Dig inside each node to find the anchor href
    // The anchor text is the real searchable item
    var HrefNodes = Nodes.children("a");
    if (!HrefNodes)
        return;

    // Add the searchableitem class so jQuery can find this item and compare search text
    // If a search match is found, a new class will be added to highlight the item
    HrefNodes.addClass("searchableitem");
}




/**
 * Filter the content by the given week
 *  0 = This week
 * -1 = Last week
 * +1 = Next week
 * @param {any} ContentType
 * @param {any} CurrentFilterJsonString
 * @param {any} nWeekOffset
 */
function AjaxFilterByWeekOffset(ContentType, CurrentFilterJsonString, nWeekOffset/*0=this, -1=last, +1=next*/) {

    if (!ContentType)
        return;

    var params = {
        "ContentType": ContentType,
        "CurrentFilterJsonString": CurrentFilterJsonString,
        "WeekOffset": nWeekOffset,
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetFilterJsonStringByWeekOffset",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                if (response.CanFilterContent) {

                    // Set the new filter into the selected content
                    SetSelectedContentPaneFilterJsonString(response.FilterJsonString);

                    // Refresh the selected content to show the new filter
                    RefreshSelectedContent();
                }
                else {
                    // "This content cannot be filtered. Select an icon from Home (All Views)."
                    $.toaster({ settings: { timeout: 10000 } });
                    $.toaster(response.FilterMessage, 'Filter', 'danger');
                    $.toaster.reset();
                }
            }
            else {
            }
        },
        error: function (xhr, status, error) {
            var errormsg = "Error " + xhr.status + ", " + xhr.statusText;
            ToastError("AjaxFilterByWeekOffset", errormsg);
            console.log('AJAX: ' + errormsg);
        }
    });
}



var bAddingFilterTreeNodes = false;

function AddAllFilterTreeNodesByCookie() {

    try {
        bAddingFilterTreeNodes = true;

        var ParentPathsArray = [];
        var NodeNamesArray = [];
        var NodeValuesArray = [];
        var NodeTypesArray = [];
        GetAllFilterTreeNodeCookies(ParentPathsArray, NodeNamesArray, NodeValuesArray, NodeTypesArray);

        for (i = 0; i < ParentPathsArray.length; ++i) {

            // Values saved in the cookie
            var ParentPath = ParentPathsArray[i];
            var NodeText = NodeNamesArray[i];
            var NodeValue = NodeValuesArray[i];
            var NodeType = NodeTypesArray[i];

            // Find the parent node to put the new item in
            var ParentNode = $("#FilterTree").igTree("nodeByPath", ParentPath);
            if (!ParentNode || ParentNode.length == 0)
                continue;
            var ParentNodeElement = ParentNode[0];
            var ParentNodeObject = $("#FilterTree").igTree("nodeFromElement", ParentNode);
            if (!ParentNodeObject)
                continue;

            // No value? Why?
            if (!NodeValue || NodeValue == null || NodeValue == 'undefined')
                NodeValue = NodeText;

            // For verification during debugging
            //var GrandParentNodeObject = GetParentTreeNode($("#FilterTree"), ParentNodeObject);
            //if (!GrandParentNodeObject || GrandParentNodeObject.length == 0)
            //    continue;

            // Does it already exist?
            var ParentNodeElementObject = $(ParentNodeElement);
            var ExistingNode = ParentNodeElementObject.find("[data-value='" + NodeValue + "']");
            if (ExistingNode && ExistingNode.length > 0)
                continue;

            // Add a new node
            var newNode = { "Text": NodeText, "ValueKey": NodeValue, "FilterType": NodeType, };
            $("#FilterTree").igTree("addNode", newNode, ParentNode);
        }

        bAddingFilterTreeNodes = false;
    }
    catch (e) {
        // Cannot show this content
        // Keeps popping up, maybe because the tree is refreshing while this code is running (gets cleared then rendered again while this code is running)
        //ToastError("Add Filter Nodes", e.name + ": " + e.message);
        bAddingFilterTreeNodes = false;
        return false;
    }
}




/**
 * Called by DateRangePicker dialog when selection is made
 * */
function OnAddCustomDateRangeFilterChoice(StartDate, EndDate) {

    var sDateRange = StartDate.toLocaleDateString() + " ~ " + EndDate.toLocaleDateString();
    var selectedNode = $("#FilterTree").igTree("selectedNode");
    var newNode = { "Text": sDateRange, "ValueKey": sDateRange, };

    // Already got a node with this value?
    var bAddedToTree = false;
    var NewDateRangeNode = $(selectedNode.element).find("[data-value='" + sDateRange + "']");

    // Add the new date range node to the tree so it can be clicked
    if (!NewDateRangeNode || NewDateRangeNode.length == 0) {
        $("#FilterTree").igTree("addNode", newNode, selectedNode.element);
        NewDateRangeNode = $(selectedNode.element).find("[data-value='" + sDateRange + "']");
        bAddedToTree = true;
    }
    var NewNodeObject = $("#FilterTree").igTree("nodeFromElement", NewDateRangeNode);

    // Expand the Custom Date Range node
    $("#FilterTree").igTree("expand", selectedNode.element);

    // Select the new node
    $('#FilterTree').igTree('select', NewDateRangeNode);

    // Filter by the new date range
    var ParentNode = GetParentTreeNode($("#FilterTree"), NewNodeObject);
    var TopLevelNode = GetTopLevelTreeNode($("#FilterTree"), NewNodeObject);
    var FilterNodeText = NewNodeObject.data.Text;
    var FilterNodeValue = NewNodeObject.data.Value;
    if (!FilterNodeValue || FilterNodeValue == null || FilterNodeValue == 'undefined')
        FilterNodeValue = NewNodeObject.data.ValueKey;
    var FilterNodeType = TopLevelNode.data.Value;
    ProcessFilterByRawNodeValues(FilterNodeText, FilterNodeValue, FilterNodeType, ParentNode.data.Text, ParentNode.data.ValueKey, TopLevelNode.data.Text, TopLevelNode.data.ValueKey);

    // Save new node to cookie so it can be re-added when the tree is refreshed
    if (bAddedToTree) {
        AddFilterTreeNodeToCookies(ParentNode.path, NewNodeObject.data.Text, NewNodeObject.data.ValueKey);
    }
}


/**
 * Prompt callback when user enters a name to filter by
 * Search by name
 * Prompt: "Enter a name to search for"
 * */
function FilterByDatabaseFieldPromptCallback(prompt, ItemNameParentNode) {

    if (!prompt)
        return;
    if (!prompt.sValue)
        return;
    if (!ItemNameParentNode)
        return;

    // Trim whitespace from prompt value
    var sNewValue = prompt.sValue;
    sNewValue = $.trim(sNewValue);
    if (!sNewValue)
        return;

    // Clicked this node
    var selectedNode = $("#FilterTree").igTree("selectedNode");
    if (!selectedNode)
        return;

    var sNewNodeFilterType = selectedNode.data.ValueKey;
    var newNode = { "Text": sNewValue, "ValueKey": sNewValue, "FilterType": sNewNodeFilterType, };

    // Already got a node with this value?
    var bAddedToTree = false;
    var NewItemNodeObject = $(selectedNode.element).find("[data-value='" + sNewValue + "']");

    // Add the new item name node to the tree so it can be clicked
    if (!NewItemNodeObject || NewItemNodeObject.length == 0) {
        $("#FilterTree").igTree("addNode", newNode, selectedNode.element);
        NewItemNodeObject = $(selectedNode.element).find("[data-value='" + sNewValue + "']");
        bAddedToTree = true;
    }
    var NewNodeObject = $("#FilterTree").igTree("nodeFromElement", NewItemNodeObject);

    // Expand the Parent node
    $("#FilterTree").igTree("expand", selectedNode.element);

    // Filter by the new item
    var ParentNode = ItemNameParentNode;
    var TopLevelNode = ItemNameParentNode;
    var FilterNodeText = sNewValue;
    var FilterNodeValue = sNewValue;
    var FilterNodeType = TopLevelNode.data.ValueKey;
    ProcessFilterByRawNodeValues(FilterNodeText, FilterNodeValue, FilterNodeType, ParentNode.data.Text, ParentNode.data.Value, TopLevelNode.data.Text, TopLevelNode.data.Value);

    // Save new node to cookie so it can be re-added when the tree is refreshed
    if (bAddedToTree) {
        AddFilterTreeNodeToCookies(ParentNode.path, FilterNodeText, FilterNodeValue, FilterNodeType);
    }
}



//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Filter button context menu
//     Show active items only
//     Show active and inactive items
//     Show inactive items only


function AjaxGetFilterTreeContextMenu(event) {

    var params = {
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetFilterTreeContextMenu",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                if (response.ContextMenuItems) {
                    var menuitems = JSON.parse(response.ContextMenuItems);
                    var menu = new ContextMenu(menuitems);
                    menu.display(event);
                }
            }
            else {
                ToastError("AjaxGetFilterTreeContextMenu", response.ErrorResults);
            }
        },
        error: function (xhr, status, error) {
            var errormsg = "Error " + xhr.status + ", " + xhr.statusText;
            ToastError("AjaxGetFilterTreeContextMenu", errormsg);
            console.log('AJAX: ' + errormsg);
        }
    });
}



function AjaxShowFilterActiveItems(sShowActive) {

    // nShowActive: 0=Active only, 1=Active and inactive, 2=Inactive only
    var params = {
        "ShowActive": sShowActive
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxShowFilterActiveItems",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                AjaxRefreshFilterTreeView($("#" + FilterTreePartialViewDivId));
            }
            else {
                ToastError("AjaxShowFilterActiveItems", response.ErrorResults);
            }
        },
        error: function (xhr, status, error) {
            var errormsg = "Error " + xhr.status + ", " + xhr.statusText;
            ToastError("AjaxShowFilterActiveItems", errormsg);
            console.log('AJAX: ' + errormsg);
        }
    });
}


function OnClickTreeFilterButton(event) {

    event.preventDefault();
    AjaxGetFilterTreeContextMenu(event);
}


function ShowFilterTreeActiveItemsOnly() {

    // nShowActive: 0=Active only, 1=Active and inactive, 2=Inactive only
    AjaxShowFilterActiveItems("0");
}

function ShowFilterTreeActiveAndInactiveItems() {

    // nShowActive: 0=Active only, 1=Active and inactive, 2=Inactive only
    AjaxShowFilterActiveItems("1");
}

function ShowFilterTreeInactiveItemsOnly() {

    // nShowActive: 0=Active only, 1=Active and inactive, 2=Inactive only
    AjaxShowFilterActiveItems("2");
}

function OnFilterByDateRange(DateRange) {

    // Good value?
    if (!DateRange) {
        ToastError("Filter by date range", "No date range value");
    }

    // Get date range value from array
    while (DateRange && Array.isArray(DateRange) && DateRange.length > 0) {
        DateRange = DateRange[0];
    }

    // Good value?
    if (!DateRange) {
        ToastError("Filter by date range", "Could not obtain date range value");
    }

    // Process now
    ProcessFilter(DateRange, DateRange, "Date range");
}





//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//




function AjaxCheckAddTreeNodeSubitems(TreeObject, ParentNode, ItemText, ItemValue, ItemType, nExpandToLevel) {

    var params = {
        "ItemText": ItemText,
        "ItemValue": ItemValue,
        "ItemType": ItemType,
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetTreeListSubitems",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {

                // Add child nodes under the clicked node
                // Examples:
                //      Subprojects under project
                //      Projects under client
                //      Project tasks under subproject
                if (response.MenuItems) {
                    var menuitems = JSON.parse(response.MenuItems);
                    if (menuitems) {
                        var ParentNodeObjectFromPath = TreeObject.igTree("nodeByPath", ParentNode.path);
                        RemoveChildNodes(TreeObject, ParentNodeObjectFromPath);
                        AddSubitemsToTreeNode(TreeObject, ParentNode, menuitems, nExpandToLevel, 0/*nLevel*/);
                        return;
                    }
                }
            }
            else {
                ToastError("AjaxCheckAddNodeSubitems", response.ErrorResults);
            }
        },
        error: function (xhr, status, error) {
            var errormsg = "Error " + xhr.status + ", " + xhr.statusText;
            ToastError("AjaxCheckAddNodeSubitems", errormsg);
            console.log('AJAX: ' + errormsg);
        }
    });
}


function AddSubitemsToTreeNode(TreeObject, ParentNode, menuitems, nExpandToLevel, nLevel) {

    if (!menuitems)
        return;
    if (menuitems.length == 0)
        return;

    for (var i = 0; i < menuitems.length; i++) {
        var menuitem = menuitems[i];
        AddSubitemToTreeNode(TreeObject, ParentNode, menuitem, nExpandToLevel, nLevel+1);
    }
}



function AddSubitemToTreeNode(TreeObject, ParentNode, menuitem, nExpandToLevel, nLevel) {

    // https://www.igniteui.com/help/api/2021.1/ui.igtree#methods:addNode
    // {Text: '10200', Value: 'AD450FF2-54FC-4847-8ED0-EF2F388C37D2', Base64ImageUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA…suHs2ciU+g31GKJGzLFBRAAAAABJRU5ErkJggg==', ChildItems: Array(0)}
    if (!TreeObject)
        return;
    if (!ParentNode)
        return;
    if (!ParentNode.path)
        return;

    var ParentNodeObjectFromPath = TreeObject.igTree("nodeByPath", ParentNode.path);
    if (!ParentNodeObjectFromPath || ParentNodeObjectFromPath.length == 0)
        return;

    // {type: null, text: 'Test', value: '100', pathname: '', icon: '<img src="data:image/png;base64,iVBORw0KGgoAAAANSU…fIMW2NIxCA90XIMAHYRkylU/9fYAAAAAElFTkSuQmCC">', …}
    if (!menuitem)
        return;

    var sFilterType = "";
    var newnode = { "Text": menuitem.text, "ValueKey": menuitem.valuekey, "FilterType": sFilterType, "Base64ImageUrl": menuitem.ImgBase64, };
    AddChildrenToTreeNodeObject(newnode, menuitem);
    var addednode = TreeObject.igTree("addNode", newnode, ParentNodeObjectFromPath);

    // How far to expand
    if (nLevel <= nExpandToLevel) {
        // Expand the parent to show the new node
        // https://www.igniteui.com/help/api/2021.1/ui.igtree#methods:expand
        TreeObject.igTree("expand", ParentNodeObjectFromPath);
    }
}

function AddChildrenToTreeNodeObject(TreeNode, menuitem) {

    if (!menuitem)
        return;
    if (!menuitem.sub)
        return;
    if (!menuitem.sub.length)
        return;

    var sFilterType = "";

    var children = [];

    var menuitems = menuitem.sub;
    for (var i = 0; i < menuitems.length; i++) {
        var menuitem = menuitems[i];
        var newnode = { "Text": menuitem.text, "ValueKey": menuitem.valuekey, "FilterType": sFilterType, "Base64ImageUrl": menuitem.ImgBase64, };
        children.push(newnode);

        // Recursively add sub-children
        AddChildrenToTreeNodeObject(newnode, menuitem);
    }

    TreeNode.ChildItems = children;
}




//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//





function FilterTreeExpandToNode(ElementObject) {
    TreeExpandToNode($("#FilterTree"), ElementObject);
}

function FilterTreeExpandAllNodes(ElementObjects) {
    TreeExpandAllNodes($("#FilterTree"), ElementObjects);
}






/**
 * Expand all parent nodes for all child nodes in the list
 * This makes the child nodes visible
 */
function TreeExpandAllNodes(TreeObject, ElementObjects) {

    if (!ElementObjects)
        return;
    if (ElementObjects.length == 0)
        return;

    // Expand only the first 20 for performance sake
    var nToExpand = Math.min(ElementObjects.length, 20);
    for (var i = 0; i < nToExpand; i++) {
        var ElementObject = $(ElementObjects[i]);
        TreeExpandToNode(TreeObject, ElementObject);
    }
}


/**
 * Expand all the parent nodes above this node
 * This makes the node visible
 * @param {any} ElementObject
 * @returns
 */
function TreeExpandToNode(TreeObject, ElementObject) {

    if (!TreeObject)
        return;
    if (TreeObject.length == 0)
        return;

    // Try going up 4 parents, looking for a "node" object
    for (var i = 0; i < 4; ++i) {

        if (!ElementObject)
            return;
        if (ElementObject.length == 0)
            return;

        // Is the element a tree node?
        // If so, expand all the parents down to this node
        var TreeNode = TreeObject.igTree("nodeFromElement", ElementObject);
        var bIsTreeNode = (TreeNode && TreeNode.element);

        // Is this a tree "node" object?
        if (bIsTreeNode) {
            TreeObject.igTree("expandToNode", TreeNode.element);
            return;
        }

        // Try the parent of this object
        // Maybe it is a tree node
        ElementObject = ElementObject.parent();
    }
}


function RemoveChildNodes(TreeObject, ElementObject) {

    if (!TreeObject)
        return;
    if (TreeObject.length == 0)
        return;
    if (!ElementObject)
        return;
    if (ElementObject.length == 0)
        return;

    var nodes = TreeObject.igTree("children", ElementObject);
    if (!nodes)
        return;

    for (var i = nodes.length-1; i >= 0; i--) {
        var node = nodes[i];
        if (node)
            TreeObject.igTree("removeAt", node.path);
    }
}

