
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Infragistics Dock Manager
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//

// Documentation
// https://www.igniteui.com/dock-manager/overview
// https://www.infragistics.com/products/ignite-ui/dock-manager/docs/typescript/latest/index.html
// https://www.infragistics.com/products/ignite-ui/dock-manager/docs/typescript/latest/interfaces/igccontentpane.html
// https://www.infragistics.com/products/ignite-ui/dock-manager/docs/typescript/latest/interfaces/igcdockmanagereventmap.html

//if (false) {
//    $("#dockManager").hide();
//    $("#error").show();
//}
//else {
//    $("#error").hide();
//    RebuildDockManagerLayout();
//}



function RebuildDockManagerLayout() {

    var dockManager = document.getElementById('dockManager');
    if (!dockManager)
        return;

    document.getElementById('dockManager').layout = {
        rootPane: {
            type: "splitPane",
            orientation: "horizontal",
            panes: [
                {
                    type: "splitPane",
                    orientation: "vertical",
                    size: 100,
                    panes: [
                        {
                            type: "contentPane",
                            contentId: "FilterPane",
                            header: "Filter",
                            allowMaximize: false,
                            unpinnedSize: 400,
                            allowClose: false,
                            isPinned: false,
                        },
                    ]
                },
                {
                    type: "splitPane",
                    orientation: "vertical",
                    size: 300,
                    panes: [
                        {
                            // Main document pane
                            type: "documentHost",
                            size: 200,
                            rootPane: {
                                type: "splitPane",
                                orientation: "horizontal",
                                panes: [
                                    {
                                        type: "tabGroupPane",
                                        panes: [
                                            //    {
                                            //        type: "contentPane",
                                            //        header: "Home (All Views)",
                                            //        allowMaximize: false,
                                            //        contentId: "content3",
                                            //        STCONTENTTYPE: "HOMEALLVIEWS",
                                            //    },
                                            //    {
                                            //        type: "contentPane",
                                            //        header: "Document 2",
                                            //        allowMaximize: false,
                                            //        contentId: "content4",
                                            //        STCONTENTTYPE: "CATEGORIESGRID",
                                            //    }
                                        ]
                                    }
                                ]
                            }
                        },
                        //    {
                        //        type: "contentPane",
                        //        contentId: "content5",
                        //        header: "Unpinned Pane 2",
                        //        allowMaximize: false,
                        //        isPinned: false
                        //    }
                    ]
                },
                {
                    type: "splitPane",
                    orientation: "vertical",
                    size: 150,
                    panes: [
                        {
                            type: "tabGroupPane",
                            size: 200,
                            panes: [
                                {
                                    type: "contentPane",
                                    contentId: "PropertyPane",
                                    allowMaximize: false,
                                    header: "Properties",
                                    allowClose: false,
                                    isPinned: false,
                                    unpinnedSize: 400,
                                },
                                //    {
                                //        type: "contentPane",
                                //        contentId: "content7",
                                //        allowMaximize: false,
                                //        header: "Tab 2"
                                //    }
                            ]
                        },
                        {
                            type: "contentPane",
                            contentId: "SettingsPane",
                            allowMaximize: false,
                            header: "Settings",
                            allowClose: false,
                            isPinned: false,
                            unpinnedSize: 400,
                        }
                    ]
                }
            ]
        },
        floatingPanes: [
            {
                type: "splitPane",
                orientation: "horizontal",
                floatingHeight: 150,
                floatingWidth: 250,
                floatingLocation: { x: 300, y: 200 },
                panes: [
                    {
                        //    type: "contentPane",
                        //    contentId: "content9",
                        //    header: "Floating Pane"
                    }
                ]
            }
        ]
    };

    RefreshDockManager();
}



/**
 * Refresh the entire dock manager
 * */
function RefreshDockManager() {

    if (!this.dockManager)
        return;
    if (!this.dockManager.layout)
        return;

    // Modifying any of the properties of the layout object will not trigger an update of the Dock Manager and the whole layout object should be replaced.
    requestAnimationFrame(() => {
        const layout = this.dockManager.layout;
        this.layout = { ...layout };
        this.dockManager.layout = { ...layout };
    });
}






/**
 * Event handlers for dock manager
 * Selected tab changed
 * Pane closed
 * Pane pinned
 * Splitter resize
 * */
function SetupDockManagerEventHandlers() {

    //console.log("Set up dockManager activePaneChanged event handlers");
    $("#dockManager").on('activePaneChanged', OnActivePaneChanged);
    $("#dockManager").on('paneClose', OnPaneClose);
    $("#dockManager").on('panePinnedToggle', OnPanePinnedToggle);
    $("#dockManager").on('splitterResizeEnd', OnSplitterResizeEnd);
}






function FindSlotByContentId(contentId) {
    // See Index.cshtml for igc-dockmanager and slots
    // contentId will equal the "slot" value (slot="content3")
    // Example: <div slot="content3" class="dockManagerContent" style="height:100%; overflow:hidden;"><div id="divRecordsetGridPartialView1" style="height: 100%; overflow: hidden; background-color: whitesmoke; font-size: calc(8pt + 0.25vw); ">Loading...</div></div>
    var SlotDiv = $("#dockManager").find(`[slot='${contentId}']`);
    if (SlotDiv)
        return SlotDiv;

    // For older JavaScript environments (ES5 and earlier):
    // https://stackoverflow.com/questions/4191386/jquery-how-to-find-an-element-based-on-a-data-attribute-value
    SlotDiv = $("div").find("[slot='" + contentId + "']");
    if (SlotDiv)
        return SlotDiv;

    // Another way
    SlotDiv = $("div[slot='" + contentId + "']");
    if (SlotDiv)
        return SlotDiv;

    // Could not find slot
    return null;
}


function FindFirstDiv(elem) {
    // The partial-view div is always the first direct-child div of the slot.
    // Use .children() not .find() — .find() traverses the entire subtree including
    // thousands of Gantt grid-line divs, causing Sizzle to recurse ~35000 times and
    // blow the call stack. .children() looks only at immediate children (2-3 nodes).
    var FirstDiv = $(elem).children('div').first();
    if (FirstDiv && FirstDiv.length > 0)
        return FirstDiv;

    // No div inside this element
    return null;
}

function FindDocumentHostPanes() {
    //type: "documentHost",
    //    size: 200,
    //        rootPane: {
    //    type: "splitPane",
    //        orientation: "horizontal",
    //            panes: [
    //                {
    //                }

    var dockManager = document.getElementById('dockManager');
    if (!dockManager)
        return null;

    //var DockManager = $("#dockManager");
    var DockManagerLayout = document.getElementById('dockManager').layout;
    if (!DockManagerLayout)
        return null;
    if (!DockManagerLayout.rootPane)
        return null;
    if (!DockManagerLayout.rootPane.panes)
        return null;
    if (!DockManagerLayout.rootPane.panes[1])
        return null;
    if (!DockManagerLayout.rootPane.panes[1].panes)
        return null;
    if (!DockManagerLayout.rootPane.panes[1].panes[0])
        return null;

    // type: "documentHost",
    var DocumentHost = DockManagerLayout.rootPane.panes[1].panes[0];
    if (!DocumentHost)
        return null;
    if (!DocumentHost.rootPane)
        return null;
    if (!DocumentHost.rootPane.panes)
        return null;
    if (!DocumentHost.rootPane.panes[0])
        return null;

    // type: "tabGroupPane",
    var DocumentHostPanesTabGroupPane = DocumentHost.rootPane.panes[0];
    if (!DocumentHostPanesTabGroupPane)
        return null;
    if (!DocumentHostPanesTabGroupPane.panes)
        return null;

    var DocumentHostPanes = DocumentHostPanesTabGroupPane.panes;

    // Hope this is it
    return DocumentHostPanes;
}




function GetSelectedContentPaneFromDocumentHost() {
    //type: "documentHost",
    //    size: 200,
    //        rootPane: {
    //    type: "splitPane",
    //        orientation: "horizontal",
    //            panes: [
    //                {
    //                }

    var dockManager = document.getElementById('dockManager');
    if (!dockManager)
        return null;

    //var DockManager = $("#dockManager");
    var DockManagerLayout = document.getElementById('dockManager').layout;
    if (!DockManagerLayout)
        return null;
    if (!DockManagerLayout.rootPane)
        return null;
    if (!DockManagerLayout.rootPane.panes)
        return null;
    if (!DockManagerLayout.rootPane.panes[1])
        return null;
    if (!DockManagerLayout.rootPane.panes[1].panes)
        return null;
    if (!DockManagerLayout.rootPane.panes[1].panes[0])
        return null;

    // type: "documentHost",
    var DocumentHost = DockManagerLayout.rootPane.panes[1].panes[0];
    if (!DocumentHost)
        return null;
    if (!DocumentHost.rootPane)
        return null;
    if (!DocumentHost.rootPane.panes)
        return null;
    if (!DocumentHost.rootPane.panes[0])
        return null;

    // type: "tabGroupPane",
    var DocumentHostPanesTabGroupPane = DocumentHost.rootPane.panes[0];
    if (!DocumentHostPanesTabGroupPane)
        return null;
    if (!DocumentHostPanesTabGroupPane.panes)
        return null;

    var DocumentHostPanes = DocumentHostPanesTabGroupPane.panes;

    if (DocumentHostPanesTabGroupPane.selectedIndex === 'undefined')
        return null;
    if (DocumentHostPanesTabGroupPane.selectedIndex == null)
        return null;
    if (DocumentHostPanesTabGroupPane.selectedIndex < 0)
        return null;
    if (DocumentHostPanesTabGroupPane.selectedIndex >= DocumentHostPanes.length)
        return null;

    var SelectedContentPane = DocumentHostPanes[DocumentHostPanesTabGroupPane.selectedIndex];
    return SelectedContentPane;
}





function FindContentPaneByContentType(ContentType) {

    var DocumentHostPanes = FindDocumentHostPanes();
    if (!DocumentHostPanes) {
        // Yikes! This is bad
        // Must rebuild the entire dock manager layout and try again
        RebuildDockManagerLayout();
        DocumentHostPanes = FindDocumentHostPanes();
        if (!DocumentHostPanes)
            return null;
    }

    // Iterate over array of panels
    for (ContentPane of DocumentHostPanes) {
        if (ContentPane.STCONTENTTYPE == ContentType)
            return ContentPane;
    }

    // No tab with this content type
    return null;
}




function FindContentPaneByContentId(ContentId) {

    if (!ContentId)
        return null;

    var DocumentHostPanes = FindDocumentHostPanes();
    if (!DocumentHostPanes) {
        // Yikes! This is bad
        // Must rebuild the entire dock manager layout and try again
        RebuildDockManagerLayout();
        DocumentHostPanes = FindDocumentHostPanes();
        if (!DocumentHostPanes)
            return null;
    }

    // Iterate over array of panels
    for (ContentPane of DocumentHostPanes) {
        if (ContentPane.contentId == ContentId)
            return ContentPane;
    }

    // No tab with this content type
    return null;
}



function FindContentPaneBySlotDivId(SlotDivId) {

    var DocumentHostPanes = FindDocumentHostPanes();
    if (!DocumentHostPanes) {
        // Yikes! This is bad
        // Must rebuild the entire dock manager layout and try again
        RebuildDockManagerLayout();
        DocumentHostPanes = FindDocumentHostPanes();
        if (!DocumentHostPanes)
            return null;
    }

    var SlotDiv = $("#" + SlotDivId);
    if (!SlotDiv)
        return null;
    var SlotContendId = SlotDiv.attr('slot');
    if (!SlotContendId)
        return null;

    // Iterate over array of panels
    for (ContentPane of DocumentHostPanes) {
        if (ContentPane.contentId == SlotContendId)
            return ContentPane;
    }

    // No tab with this content type
    return null;
}

function FindContentPaneByValueString(ValueString) {

    var DocumentHostPanes = FindDocumentHostPanes();
    if (!DocumentHostPanes) {
        // Yikes! This is bad
        // Must rebuild the entire dock manager layout and try again
        RebuildDockManagerLayout();
        DocumentHostPanes = FindDocumentHostPanes();
        if (!DocumentHostPanes)
            return null;
    }

    // Iterate over array of panels
    for (ContentPane of DocumentHostPanes) {
        if (ContentPane.ValueString == ValueString)
            return ContentPane;
    }

    // No tab with this content type
    return null;
}




function GetNumContentPanes() {

    var DocumentHostPanes = FindDocumentHostPanes();
    if (!DocumentHostPanes)
        return 0;
    return DocumentHostPanes.length;
}


var NextUniqueNum = "1";
function GetUniqueId(prefix) {
    var d = new Date().getTime();
    d += (parseInt(Math.random() * 100)).toString();
    if (undefined === prefix) {
        prefix = 'uid-';
    }
    d = prefix + d;
    d += "-" + NextUniqueNum;
    NextUniqueNum++;
    return d;
}



/**
 * Add new tab
 * @param {any} STCONTENTTYPE
 * @param {any} ValueString
 * @param {any} title
 */
function AddDocumentTab(STCONTENTTYPE, UniqueId, ValueString, title, FilterJsonString, SettingsJsonString) {

    if (!UniqueId)
        UniqueId = GetUniqueId();

    // Add tab to the document host
    var DocumentHostPanes = FindDocumentHostPanes();
    if (!DocumentHostPanes) {
        // Yikes! This is bad
        // Must rebuild the entire dock manager layout and try again
        RebuildDockManagerLayout();
        DocumentHostPanes = FindDocumentHostPanes();
        if (!DocumentHostPanes)
            return null;
    }

    // Create DIVs for the content
    // The first div is a "slot", the inner div hosts the partial view from Ajax
    // See Index.cshtml
    // <div slot="content3" class="dockManagerContent" style="height:100%; overflow:hidden;"><div id="divRecordsetGridPartialView1" style="height: 100%; overflow: hidden; background-color: whitesmoke; font-size: calc(8pt + 0.25vw); ">Loading...</div></div>
    var NewContentId = GetUniqueId("DockManager-");
    var SlotDiv = AddNewDockManagerSlotContentDiv(NewContentId, STCONTENTTYPE);

    // New tab info
    // The contentId must match the content div "slot" attribute
    // Example: slot = 'content2'
    var NewContentPane = {
        type: "contentPane",
        header: title,
        contentId: NewContentId, // slot='contentid'
        STCONTENTTYPE: STCONTENTTYPE,
        UniqueId: UniqueId,
        ValueString: ValueString,
        FilterJsonString: FilterJsonString,
        SettingsJsonString: SettingsJsonString,
        allowMaximize: false,
    };

    // Add to array of tabs
    // Modifying any of the properties of the layout object will not trigger an update of the Dock Manager and the whole layout object should be replaced.
    const layout = this.dockManager.layout;
    layout.rootPane.panes[1].panes[0].rootPane.panes[0].panes.push(NewContentPane);
    this.layout = { ...layout };
    this.dockManager.layout = { ...layout };

    // Activate the new tab "by pane" if the UI action requires it
    return NewContentPane;
}


function AddNewDockManagerSlotContentDiv(NewContentId, ContentType) {

    // Create a "slot" div for the dock manager content
    // The "slot" attribute coorisponds to the ContentPanel.contentId
    // See Index.cshtml
    // <div slot="content3" class="dockManagerContent" style="height:100%; overflow:hidden;"><div id="divRecordsetGridPartialView1" style="height: 100%; overflow: hidden; background-color: whitesmoke; font-size: calc(8pt + 0.25vw); ">Loading...</div></div>
    var SlotDiv = jQuery('<div>', {
        id: GetUniqueId("DockManagerContentSlotDiv-"),
        slot: NewContentId,
        class: 'dockManagerContent',
        ContentType: ContentType,
    });
    SlotDiv.appendTo('#dockManager');

    // Create a div inside the slot for a partial view
    // The contents of this div will be filled by Ajax
    var PartialViewDivId = "PartialViewDiv-" + NewContentId + "-" + ContentType;
    var PartialViewDiv = jQuery('<div>', {
        id: PartialViewDivId,
        class: 'dockManagerPartialView searchablediv',
        ContentType: ContentType,
    });
    PartialViewDiv.appendTo(SlotDiv);

    // Add some text to tell user the partial view is being loaded by Ajax
    // Lazy loading image will trigger a call to Ajax only when viewed
    var sPartialViewHtml = "";
    sPartialViewHtml += "<br>&nbsp;";
    sPartialViewHtml += "Loading...";
    var LoaderId = "PartialViewLoader-" + GetUniqueId();
    sPartialViewHtml += "<br>";
    sPartialViewHtml += "<input id=\"" + LoaderId + "\" type=\"button\" value=\"Reload\" onclick=\"RefreshPartialViewFromHtmlElement($(this))\" class=\"transitiontovisible1\">";
    PartialViewDiv.html(sPartialViewHtml);

    // Lazy loader
    // This triggers a callback only when the user sees this html element
    // Nothing happens until the element becomes visible
    onVisible(document.querySelector("#" + LoaderId), RefreshPartialViewFromHtmlElement);

    return SlotDiv;
}





function ActivateDocumentTabByContentType(STCONTENTTYPE) {

    // Find the existing panel
    var ExistingContentPane = FindContentPaneByContentType(STCONTENTTYPE);
    if (!ExistingContentPane)
        return;

    //console.log("ActivateDocumentTabByContentType ExistingContentPane.contentId: " + ExistingContentPane.contentId);

    // OLD: fixed 500ms blind timeout — unreliable on slow machines and suppressed by the
    // LastActivePaneChangedId duplicate guard if the event fired once during tab construction.
    //setTimeout(function () { RequestAnimationFrameActivePane(ExistingContentPane); }, 500);

    // FIX #1: Clear the duplicate guard so OnActivePaneChanged is not suppressed when the
    // activation event fires. Without this, a prior activePaneChanged for the same pane
    // (fired during tab construction) would cause the startup activation to be silently ignored.
    LastActivePaneChangedId = "";

    // FIX #2: Retry activation until OnActivePaneChanged confirms it landed by checking
    // HiddenSelectedContentTypeId. Each AddDocumentTab call queues an async layout render
    // on the dock manager web component — activation attempted before those renders complete
    // is silently lost. Polling self-corrects regardless of machine speed or tab count.
    var nAttempts = 0;
    var nMaxAttempts = 20;
    function tryActivate() {
        nAttempts++;

        // Re-fetch on every attempt: AddDocumentTab spreads the layout object each time it adds
        // a tab, so the reference captured before the loop may point to a stale copy.
        var FreshPane = FindContentPaneByContentType(STCONTENTTYPE);
        if (FreshPane)
            RequestAnimationFrameActivePane(FreshPane);

        setTimeout(function () {
            var sCurrentType = $('input[id="HiddenSelectedContentTypeId"]').val();
            if (!sCurrentType || sCurrentType !== STCONTENTTYPE) {
                if (nAttempts >= nMaxAttempts) {
                    // activePaneChanged never fired — synthesize the call directly so the hidden
                    // inputs and filter/settings panels are still updated without going through
                    // the dock manager event path (which may be blocked at startup).
                    var FallbackPane = FindContentPaneByContentType(STCONTENTTYPE);
                    if (FallbackPane) {
                        LastActivePaneChangedId = "";
                        OnActivePaneChanged({ detail: { newPane: FallbackPane } });
                    }
                } else {
                    LastActivePaneChangedId = "";
                    tryActivate();
                }
            }
        }, 100);
    }
    tryActivate();
}




// Activates a dock manager content pane, equivalent to the user clicking its tab.
// Uses requestAnimationFrame to defer the assignment until the dock manager is ready.
function RequestAnimationFrameActivePane(ContentPane) {

    // requestAnimationFrame defers the callback until just before the browser's next repaint.
    // This gives the dock manager web component time to finish processing any pending layout
    // changes before we modify activePane, avoiding silent drops that occur when the component
    // is mid-render and not yet ready to accept the assignment.
    requestAnimationFrame(() => {
        // Null then re-set in the same frame so the dock manager always sees a genuine
        // pane change and fires activePaneChanged — without this, assigning the same
        // pane that is already internally active produces no event.
        this.dockManager.activePane = null;
        this.dockManager.activePane = ContentPane;
    });
}




function ActivateCurrentSelectedTab() {

    var ActivePane = this.dockManager.activePane;
    if (ActivePane == null)
        return;

    // Set the active pane
    // This is necessary to activate just like a mouse click
    requestAnimationFrame(() => {
        this.dockManager.activePane = ActivePane;
    });
}

function ActivateDocumentTabByPane(ContentPane) {

    if (bSmallSizeApp)
        return;
    if (!this.dockManager)
        return;

    // Set the active pane
    // This is necessary to activate just like a mouse click
    requestAnimationFrame(() => {
        this.dockManager.activePane = ContentPane;
    });
}


function CloseContentPane(ContentPane) {

    if (ContentPane == null)
        return;
    var idxContentPane = GetContentTabIndex(ContentPane);
    if (idxContentPane < 0)
        return;

    var NextPane = GetNextOrAdjacentPane(ContentPane);
    // ******* MAY BE NULL ********

    // Modifying any of the properties of the layout object will not trigger an update of the Dock Manager and the whole layout object should be replaced.
    const layout = this.dockManager.layout;
    var panes = layout.rootPane.panes[1].panes[0].rootPane.panes[0].panes;
    panes.splice($.inArray(ContentPane, panes), 1);
    this.layout = { ...layout };
    this.dockManager.layout = { ...layout };

    // Activate the last pane
    if (NextPane)
        RequestAnimationFrameActivePane(NextPane);

    RefreshDockManager();
}


function CloseAllContentPanes() {

    if (bSmallSizeApp) {
        ClearSmallAppContentDiv();
        AddLoginButtonToSmallAppContentDiv();
    }
    else {
        // Clear all panes
        const layout = this.dockManager.layout;
        layout.rootPane.panes[1].panes[0].rootPane.panes[0].panes = [];
        this.layout = { ...layout };
        this.dockManager.layout = { ...layout };

        RefreshDockManager();

        SaveDockManagerLayoutToCookie();
    }
}


function GetContentTabIndex(ContentPane) {

    const layout = this.dockManager.layout;
    var panes = layout.rootPane.panes[1].panes[0].rootPane.panes[0].panes;
    if (!panes)
        return -1;
    return $.inArray(ContentPane, panes);
}

function GetNextOrAdjacentPane(ContentPane) {

    var idxContentPane = GetContentTabIndex(ContentPane);
    if (idxContentPane < 0)
        return null;

    const layout = this.dockManager.layout;
    var panes = layout.rootPane.panes[1].panes[0].rootPane.panes[0].panes;
    if (!panes || panes.length < 2)
        return null;

    var idxNewPane = idxContentPane + 1;
    if (idxNewPane >= panes.length)
        idxNewPane = idxContentPane - 1;
    if (idxNewPane < 0)
        return null;
    if (idxNewPane >= panes.length)
        return null;
    var NextPane = panes[idxNewPane];
    return NextPane;
}


function CloseContentPaneByValueString(ValueString) {

    var ContentPane = FindContentPaneByValueString(ValueString);
    CloseContentPane(ContentPane);

    // Save the entire layout to a cookie
    setTimeout(SaveDockManagerLayoutToCookie, 500);
}


function GetDockManagerActivePane() {

    var ActivePane = this.dockManager.activePane;
    return ActivePane;
}

function GetSelectedContentPartialViewDivId() {

    var PartialViewDivId = $('input[id="HiddenSelectedContentPartialViewDivId"]').val();
    return PartialViewDivId;
}

function GetSelectedContentPartialViewDivElement() {

    var PartialViewDivId = GetSelectedContentPartialViewDivId();
    if (!PartialViewDivId)
        return null;
    return $("#" + PartialViewDivId);
}


function GetSelectedContentPane() {

    // First, try to get selected pane from document host object
    var SelectedContentPane = GetSelectedContentPaneFromDocumentHost();
    if (SelectedContentPane)
        return SelectedContentPane;

    // Another more reliable way before resorting to the OLD way below
    var ContentId = $('input[id="HiddenSelectedContentDivId"]').val();
    SelectedContentPane = FindContentPaneByContentId(ContentId);
    if (SelectedContentPane)
        return SelectedContentPane;

    // OLD way
    // This works, but has a bug where it first the first pane by this content type rather then the selected one
    // The bug appears when two report tabs are open and try try to export. It will export the first report tab
    var ContentType = $('input[id="HiddenSelectedContentTypeId"]').val();
    if (!ContentType)
        return null;

    // Find an existing pane by this type of data
    SelectedContentPane = FindContentPaneByContentType(ContentType);
    return SelectedContentPane;
}

function GetSelectedContentType() {

    if (bSmallSizeApp)
        return GetCurrentContentType();

    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return "";
    return SelectedContentPane.STCONTENTTYPE;
}

function GetSelectedContentTitle() {

    if (bSmallSizeApp)
        return GetCurrentContentTitle();

    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return "";
    return SelectedContentPane.header;
}

function GetSelectedContentPaneFilterJsonString() {

    if (bSmallSizeApp)
        return GetCurrentFilterJsonString();

    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return "";
    return SelectedContentPane.FilterJsonString;
}

function GetSelectedContentPaneSettingsJsonString() {

    if (bSmallSizeApp)
        return GetCurrentSettingsJsonString();

    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return "";
    return SelectedContentPane.SettingsJsonString;
}

function GetSelectedContentPaneValueString() {

    if (bSmallSizeApp)
        return GetCurrentValueString();

    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return "";
    return SelectedContentPane.ValueString;
}

function GetSelectedContentPaneUniqueId() {

    if (bSmallSizeApp)
        return GetCurrentUniqueId();

    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return "";
    return SelectedContentPane.UniqueId;
}



function SetSelectedContentPaneFilterJsonString(NewFilterJsonString) {

    SaveSelectedPaneFilterJsonStringToCookie(NewFilterJsonString);

    // Filter the current view
    if (bSmallSizeApp) {
        CurrentFilterJsonString = NewFilterJsonString;
        AddToContentArray(CurrentContentType, CurrentUniqueId, CurrentValueString, CurrentContentTitle, NewFilterJsonString, CurrentSettingsJsonString);
        SetCurrentContentFilterJsonString(NewFilterJsonString);
        RefreshSmallAppContentByValues(CurrentContentType, CurrentValueString, NewFilterJsonString, CurrentSettingsJsonString);
        return;
    }

    var SelectedContentPane = GetSelectedContentPane();
    if (SelectedContentPane != null) {
        SelectedContentPane.FilterJsonString = NewFilterJsonString;
        //console.log("SelectedContentPane.UniqueId: " + SelectedContentPane.UniqueId);

        // Reset DOM value
        requestAnimationFrame(() => {
            this.dockManager.activePane = SelectedContentPane;

            // Save the entire layout to a cookie
            setTimeout(SaveDockManagerLayoutToCookie, 500);
        });
    }
}

function SetSelectedContentPaneSettingsJsonString(NewSettingsJsonString) {

    SaveSelectedPaneSettingsJsonStringToCookie(NewSettingsJsonString);

    // Settings for the current view
    if (bSmallSizeApp) {
        CurrentSettingsJsonString = NewSettingsJsonString;
        AddToContentArray(CurrentContentType, CurrentUniqueId, CurrentValueString, CurrentContentTitle, CurrentFilterJsonString, NewSettingsJsonString);
        SetCurrentContentSettingsJsonString(NewSettingsJsonString);
        RefreshSmallAppContentByValues(CurrentContentType, CurrentValueString, CurrentFilterJsonString, NewSettingsJsonString);
        return;
    }

    var SelectedContentPane = GetSelectedContentPane();
    if (SelectedContentPane != null) {
        SelectedContentPane.SettingsJsonString = NewSettingsJsonString;

        // Reset DOM value
        requestAnimationFrame(() => {
            this.dockManager.activePane = SelectedContentPane;

            // Save the entire layout to a cookie
            setTimeout(SaveDockManagerLayoutToCookie, 500);
        });
    }
}

function SetSelectedContentPaneValueString(NewValueString) {

    // Settings for the current view
    if (bSmallSizeApp) {
        CurrentValueString = NewValueString;
        return;
    }

    var SelectedContentPane = GetSelectedContentPane();
    if (SelectedContentPane != null) {
        SelectedContentPane.ValueString = NewValueString;

        // Reset DOM value
        requestAnimationFrame(() => {
            this.dockManager.activePane = SelectedContentPane;

            // Save the entire layout to a cookie
            setTimeout(SaveDockManagerLayoutToCookie, 500);
        });
    }
}


function GetSelectedContentInformationDiv() {

    if (bSmallSizeApp) {
        var SmallAppContentDiv = $("#" + SmallAppContentDivId);
        if (!SmallAppContentDiv)
            return null;

        var ContentDiv = SmallAppContentDiv.find('.contentdiv');
        if (!ContentDiv)
            return null;
        if (!ContentDiv[0])
            return null;
        return ContentDiv;
    }

    // Full app
    // Start with content pane and slot div
    // Then find the 'contentdiv' inside
    // The 'contentdiv' is the real information, without controls
    var SelectedContentPane = GetSelectedContentPane();
    if (!SelectedContentPane)
        return null;

    var SlotDiv = FindSlotByContentId(SelectedContentPane.contentId);
    if (!SlotDiv)
        return "";

    var ContentDiv = SlotDiv.find('.contentdiv');
    if (!ContentDiv)
        return null;
    if (!ContentDiv[0])
        return null;
    return ContentDiv;
}


/**
 * Get the last sql script used on the active content page
 * @returns
 */
function GetSelectedSqlScript() {
    // Div with the real information in it
    var ContentDiv = GetSelectedContentInformationDiv();
    if (!ContentDiv)
        return null;

    var sSqlScript = $(ContentDiv).find('.HiddenSqlQueryScript').val();
    return sSqlScript;
}




/**
 * Show the content type either by finding an existing pane or by adding a new one
 * @param {any} STCONTENTTYPE
 * @param {any} title
 */
function ShowStContent(STCONTENTTYPE, ValueString, title, FilterJsonString, SettingsJsonString) {

    if (!STCONTENTTYPE || STCONTENTTYPE.length == 0)
        return;
    //console.log("ShowStContent: " + STCONTENTTYPE + ", " + title);

    if (bSmallSizeApp) {
        SmallAppShowStContent(STCONTENTTYPE, GetUniqueId(), ValueString, title);
        return;
    }

    var ExistingContentPanel = FindContentPaneByContentType(STCONTENTTYPE);
    if (!ExistingContentPanel)
        ExistingContentPanel = AddDocumentTab(STCONTENTTYPE, GetUniqueId(), ValueString, title, FilterJsonString, SettingsJsonString);
    ActivateDocumentTabByPane(ExistingContentPanel);

    // Save the entire layout to a cookie
    setTimeout(SaveDockManagerLayoutToCookie, 500);
}



/**
 * Find the selected content type, and update that MVC partial view with Ajax
 * */
function RefreshActiveDockPane() {
    try {
        //console.log("RefreshActiveDockPane Begin");

        if (bSmallSizeApp) {
            RefreshSmallAppCurrentContent();
            return;
        }

        // Find an existing pane by this type of data
        var SelectedContentPane = GetSelectedContentPane();
        if (!SelectedContentPane)
            return;

        //console.log("RefreshActiveDockPane contentId: " + SelectedContentPane.contentId);

        var SlotDiv = FindSlotByContentId(SelectedContentPane.contentId);
        if (!SlotDiv)
            return;

        // Find the first div inside this slot
        // This first div is the partial view div that will contain the MVC View
        // See HomeController.cs GetPartialViewByContentType()
        // Replace the contents of this first div with a partial view from HomeController.cs
        var PartialViewDiv = FindFirstDiv(SlotDiv);
        if (!PartialViewDiv)
            return;

        //console.log("RefreshActiveDockPane: Refresh partial view");

        var ContentType = GetSelectedContentType();
        AjaxRefreshPartialViewByContentType(PartialViewDiv, ContentType, SelectedContentPane.ValueString);
    } catch (e) {
        ToastError("RefreshActiveDockPane", e.name + ": " + e.message + "\n" + e.stack);
    }
}



function RefreshDockPaneBySlotDivId(SlotDivId) {

    //console.log("RefreshDockPaneBySlotDivId: " + ContentType);

    var SlotDiv = $("#" + SlotDivId);
    if (!SlotDiv)
        return;

    var Pane = FindContentPaneBySlotDivId(SlotDivId);
    if (!Pane)
        return;

    var ContentType = $(SlotDiv).attr("ContentType");

    // Find the first div inside this slot
    // This first div is the partial view div that will contain the MVC View
    // See HomeController.cs GetPartialViewByContentType()
    // Replace the contents of this first div with a partial view from HomeController.cs
    var PartialViewDiv = FindFirstDiv(SlotDiv);
    if (!PartialViewDiv)
        return;

    //console.log("RefreshDockPaneBySlotDivId: Refresh partial view");

    AjaxRefreshPartialViewByContentType(PartialViewDiv, ContentType, Pane.ValueString);
}



/**
 * Called from img onload for an image placed in a partial view div for the purpose of triggering an update to that view
 * Refresh the MVC partial view where this image is located
 * @param {any} element
 */
function RefreshPartialViewFromHtmlElement(element) {

    // Start with the img element this function was triggered from
    // img.onload called this function
    // Then find the divs this img is located in
    // Replace the contents of the partial view div from HomeController.cs GetPartialViewByContentType()
    if (!element)
        return;

    // Convert a raw html element to jQuery
    element = $(element);

    var elementid = element.attr('id');
    if (!elementid)
        return;

    // Make visible, just in case the element opacity is 0
    // Useful for "Reload" buttons in partial views for cases where the view failed to load the first time
    // User can click this Reload button now that it is visible (but give the view a chance to load normally before making visible)
    setTimeout(function () { if ($("#"+elementid)) { $("#"+elementid).addClass('transitiontovisible2'); } }, 3000);

    // Get the partial view this image is inside
    // This will be replaced by an Ajax call to HomeController.cs GetPartialViewByContentType()
    var PartialViewDiv = $(element).parent();
    if (!PartialViewDiv)
        return;
    var PartialViewDivId = PartialViewDiv.attr('id');
    if (!PartialViewDivId)
        return;

    // Get the "slot" div this partial view div is inside
    // The "slot" div contains information about this content
    // This information can be used to refresh the partial view inside it
    var SlotDiv = $(PartialViewDiv).parent();
    if (!SlotDiv)
        return;
    var SlotDivId = SlotDiv.attr('id');
    if (!SlotDivId)
        return;
    var SlotContendId = SlotDiv.attr('slot');
    if (!SlotContendId)
        return;
    var ContentType = SlotDiv.attr('ContentType');
    if (!ContentType)
        return;

    RefreshDockPaneBySlotDivId(SlotDivId);
}





var LastActivePaneChangedId = "";


/**
 * DockManager Event: The active pane has changed
 * @param {any} event
 */
function OnActivePaneChanged(event) {
    if (!event)
        return;
    if (!event.detail)
        return;
    if (!event.detail.newPane)
        return;

    // Testing to see if OnActivePaneChanged fires
    // There was a lot of trouble with intermittant firing at startup
    // The solution was in RequestAnimationFrameActivePane, specifically to first set dockManager.activePane = null
    // Setting dockManager.activePane = null forces an internal change in dockManager so that the event would fire reliably
    //ToastMessage("OnActivePaneChanged: contentId=" + event.detail.newPane.contentId + ", STCONTENTTYPE=" + event.detail.newPane.STCONTENTTYPE);

    if (!event.detail.newPane.contentId)
        return;
    if (!event.detail.newPane.STCONTENTTYPE)
        return;

    //console.log("OnActivePaneChanged: " + event.detail.newPane.contentId + ", " + event.detail.newPane.STCONTENTTYPE);
    //console.log("OnActivePaneChanged: " + Error().stack);

    // Ignore repeat calls
    // This function is called repeatedly with the same Ids, which makes pane flicker and refill needlessly
    var CombinedId = event.detail.newPane.contentId + "" + event.detail.newPane.STCONTENTTYPE;
    if (LastActivePaneChangedId == CombinedId)
        return;
    LastActivePaneChangedId = CombinedId;

    // Must first find the first div inside the "slot"
    // Begin by finding the slot with this contentid
    // See Index.cshtml for igc-dockmanager and slots
    // contentId will equal the "slot" value (slot="content3")
    // Example: <div slot="content3" class="dockManagerContent" style="height:100%; overflow:hidden;"><div id="divRecordsetGridPartialView1" style="height: 100%; overflow: hidden; background-color: whitesmoke; font-size: calc(8pt + 0.25vw); ">Loading...</div></div>
    //var SlotDiv = $("#dockManager").find(`[slot='${event.detail.newPane.contentId}']`);
    var SlotDiv = FindSlotByContentId(event.detail.newPane.contentId);
    if (!SlotDiv)
        return;

    //console.log("OnActivePaneChanged Slot Content Id: " + event.detail.newPane.contentId);

    // Find the first div inside this slot
    // Replace the contents of this first div with a partial view
    //var FirstDiv = $('div:first', $(SlotDiv));
    var FirstDiv = FindFirstDiv(SlotDiv);
    if (!FirstDiv)
        return;

    var SlotDivId = $(SlotDiv).attr('id');
    var FirstDivId = $(FirstDiv).attr('id');
    //console.log("OnActivePaneChanged SlotDivId, FirstDivId: " + SlotDivId + ", " + FirstDivId);

    // Save the content type in a hidden value for use by Ajax
    var ContentType = event.detail.newPane.STCONTENTTYPE;
    var HeaderText = event.detail.newPane.header;
    var ContentId = event.detail.newPane.contentId;
    var ValueString = event.detail.newPane.ValueString;
    $('input[id="HiddenSelectedContentTypeId"]').val(ContentType);
    $('input[id="HiddenSelectedContentHeaderId"]').val(HeaderText);
    $('input[id="HiddenSelectedContentDivId"]').val(ContentId);
    $('input[id="HiddenSelectedContentValueStringId"]').val(ValueString);
    $('input[id="HiddenSelectedContentSlotDivId"]').val(SlotDivId);
    $('input[id="HiddenSelectedContentPartialViewDivId"]').val(FirstDivId);

// DO NOT refresh the view now. It sometimes blocks button clicks inside the new view
    // Ajax function to replace div contents with partial view from server
    //AjaxRefreshPartialViewByContentType(FirstDiv, ContentType);

    // Refresh the filter and settings view for this type of content
    if (!bSmallSizeApp) {
        AjaxRefreshFilterTreeView($("#" + FilterTreePartialViewDivId));
        AjaxRefreshSettingsGridView($("#" + SettingsGridPartialViewDivId), ContentType);
    }

    //ToastMessage("ContentType", ContentType);

    setTimeout(function () { OnEndActivePaneChanged(ContentType); }, 100);

    // Save the entire layout to a cookie, including the active pane
    setTimeout(SaveDockManagerLayoutToCookie, 500);
}

function OnEndActivePaneChanged(ContentType) {

    // No longer applicable to the new page
    CloseGridEditPopupDialog();

    if (ContentType != "REPORTVIEW")
        CloseReportDesignTools();

    if (ContentType == "BARCODESCAN")
        SetBarcodeInputFocus();
    else if (ContentType == "REPORTVIEW")
        CheckOpenReportDesignTools();

    // Have database records for the selected content changed?
    // If so, refresh the page
    CheckSelectedContentChangeRefresh();
}



/**
 * An event raised when panes are about to close.
 * @param {any} event
 */
function OnPaneClose(event) {
    if (!event)
        return;
    if (!event.detail)
        return;

    if (event.detail && event.detail.sourcePane && event.detail.sourcePane.STCONTENTTYPE) {

        // Delete SlotDiv because they cause duplicate ids when the same type page is opened
        //     Example: Open and close "Time logs" multiple times
        //     Result: Multiple "DockManagerContentSlotDiv-xxx" will be orphaned and unused
        var SlotDiv = FindSlotByContentId(event.detail.sourcePane.contentId);
        if (SlotDiv && SlotDiv.length > 0)
            SlotDiv.remove();

        // Delete cookies so they don't proliferate
        DeleteContentCookies(event.detail.sourcePane.STCONTENTTYPE, event.detail.sourcePane.UniqueId);
    }

    // Save the entire layout to a cookie, including the active pane
    setTimeout(SaveDockManagerLayoutToCookie, 500);
}




/**
 * Event is raised when a pane gets pinned or unpinned
 * Typically called for Filter and Properties panes
 * @param {any} event
 */
function OnPanePinnedToggle(event) {
    if (!event)
        return;
    if (!event.detail)
        return;

    // Event details
    // https://www.infragistics.com/products/ignite-ui/dock-manager/docs/typescript/latest/interfaces/igcpanepinnedeventargs.html

    var IsPinned = event.detail.newValue;
    var ContentId = event.detail.sourcePane.contentId;
    SavePanelPinnedToCookie(ContentId, IsPinned);
}





/**
 * Event is raised when a splitter is moved
 * Typically called for Filter and Properties panes
 * @param {any} event
 */
function OnSplitterResizeEnd(event) {
    if (!event)
        return;

    // event.detail is null
    //var Splitter = event.target;

    // Save all splitter sizes
    SaveSplitterPaneSizesToCookie();
}






function FindPaneByContentId(contentId) {

    if (!contentId)
        return null;

    var dockManager = document.getElementById('dockManager');
    if (!dockManager)
        return null;

    var DockManagerLayout = document.getElementById('dockManager').layout;
    if (!DockManagerLayout)
        return null;

    // Search panes
    return FindPaneWithinPanesByContentId(DockManagerLayout.rootPane.panes, contentId);
}


function FindPaneWithinPanesByContentId(panes, contentId) {

    if (!panes)
        return null;
    if (!contentId)
        return null;

    for (const pane of panes) {
        if (pane.contentId === contentId)
            return pane;

        // Search children inside this pane
        var found = FindPaneWithinPanesByContentId(pane.panes, contentId);
        if (found)
            return found;
    }

    // Not found
    return null;
}






/**
 * Find the specified pane and make it visible
 * Set isPinned to true to show a pane
 * @param {any} contentid
 * @param {any} showit
 */
function ShowPaneByContentId(contentid, showit) {

    var Pane = FindPaneByContentId(contentid);
    if (Pane)
        Pane.isPinned = showit;
}


function ShowFilterPane() {

    if (bSmallSizeApp) {
        AjaxRefreshFilterTreeView($("#"+FilterTreePartialViewDivId));
        AddFilterTreeToContentArray();
        return;
    }

    ShowPaneByContentId("FilterPane", true);
    RefreshDockManager();
    SaveFilterPanelPinnedToCooke();
}

function ShowPropertiesPane() {

    // Nothing to do for small app
    if (bSmallSizeApp)
        return;

    ShowPaneByContentId("PropertyPane", true);
    RefreshDockManager();
    SavePropertyPanelPinnedToCooke();
}

function OnShowPropertiesPaneMenuClick() {

    if (bSmallSizeApp) {
        ToastMessage("Select a content row to view properties");
        return;
    }

    ShowPropertiesPane();
}

function ShowSettingsPane() {

    var ContentType = GetSelectedContentType();

    if (bSmallSizeApp) {
        AjaxRefreshSettingsGridView($("#"+SettingsGridPartialViewDivId), ContentType);
        return;
    }

    ShowPaneByContentId("SettingsPane", true);
    RefreshDockManager();
    SaveSettingsPanelPinnedToCooke();
}





/**
 * Get the "size" value for a given pane index
 * @param {any} nSplitterPaneIdx
 */
function GetSplitterPaneSize(nSplitterPaneIdx) {

    var dockManager = document.getElementById('dockManager');
    if (!dockManager)
        return -1;

    var DockManagerLayout = document.getElementById('dockManager').layout;
    if (!DockManagerLayout)
        return -1;

    // Good index?
    if (DockManagerLayout.rootPane.panes.length <= nSplitterPaneIdx)
        return -1;

    var Pane = DockManagerLayout.rootPane.panes[nSplitterPaneIdx];
    if (Pane && Pane.size)
        return Pane.size.toFixed(4);
    return -1;
}



/**
 * Set the "size" value for a given pane index
 * @param {any} nSplitterPaneIdx
 * @param {any} nPaneSize
 */
function SetSplitterPaneSize(nSplitterPaneIdx, nPaneSize) {

    var DockManagerLayout = document.getElementById('dockManager').layout;
    if (!DockManagerLayout)
        return;

    // Good index?
    if (DockManagerLayout.rootPane.panes.length <= nSplitterPaneIdx)
        return;

    var Pane = DockManagerLayout.rootPane.panes[nSplitterPaneIdx];
    if (Pane)
        Pane.size = nPaneSize;
}

function HideDockManager() {
    $("#dockManager").hide();
}

function ShowDockManager() {
    $("#dockManager").show();
}



function CheckSelectedContentChangeRefresh() {

    var ContentType = GetSelectedContentType();
    AjaxIsContentTypeUpdated(ContentType);
}

/**
 * Check to see if any database records have changed for this data type
 * Refresh the page if data has changed
 * Example: Barcodes are scanned, which updates time logs, so the Time Logs page should be updated
 * @param {any} ContentType
 */
function AjaxIsContentTypeUpdated(ContentType) {

    var params = {
        "ContentType": ContentType,
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxIsContentTypeUpdated",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json",
        success: function (response) {
            if (response.Success) {
                if (response.ContentChanged) {
                    RefreshSelectedContent();
                    ToastMessage("Auto-refresh", "Data has changed");
                }
            }
            else {
                ToastError("AjaxIsContentTypeUpdated", response.ErrorResults);
            }
        },
        error: function (xhr, status, error) {
            var errormsg = "Error " + xhr.status + ", " + xhr.statusText;
            ToastError("AjaxIsContentTypeUpdated", errormsg);
            console.log('AJAX: ' + errormsg);
        }
    });
}








