
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Ajax calls to refresh views
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//

var SmallAppContentDivId = "SmallAppContentDivId";
var PropertyGridPartialViewDivId = "PropertyGridPartialViewDivId";
var ActivePropertyGridPartialViewDivId = "PropertyGridPartialViewDivId";
var SettingsGridPartialViewDivId = "SettingsGridPartialViewDivId";
var FilterTreePartialViewDivId = "FilterTreePartialViewDivId";


//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Refresh the filter tree view
// Use the div element to refresh
// Example: "FilterTreePartialViewDivId"
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
function AjaxRefreshFilterTreeView(divElement) {

    // Check the last time a filter was processed, so tree isn't refreshed just after clicking a filter item
    if (LastApplyFilterTime) {
        var Now = new Date();
        var millisecondsSinceLast = Now.getTime() - LastApplyFilterTime.getTime();
        if (millisecondsSinceLast < 250)
            return;
    }

    // Gets in the way of the properties panel
    if (bSmallSizeApp)
        CloseGridEditPopupDialog();

    AjaxRefreshPartialView(divElement, "AjaxGetFilterTreePartialView");

    //ToastMessage("AjaxRefreshFilterTreeView", "refresh");
    //console.log("AjaxRefreshFilterTreeView: " + Error().stack);
}



//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Refresh a property grid view
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
/**
 * Refresh a property grid view using hidden values
 * Use the div element to refresh
 * Example: "divRecordsetGridPartialView"
 * @param {any} divElement
 */
function RefreshPropertyGridViewFromHiddenSelection(divElement) {

    if (!divElement || divElement.length == 0) {
        console.log("RefreshPropertyGridView div does not exist!");
        return;
    }

    // These parameters tell the property grid what to display
    // Examples:
    //          stdata.BaseDataSet
    //          wipdata.wipitem
    //          radata.raitem
    var SelectedDataType = $("#HiddenSelectedDataTypeId").val();
    var SelectedTable = $("#HiddenSelectedTableId").val();
    var SelectedColumnId = $("#HiddenSelectedColumnId").val();
    var SelectedRecordId = $("#HiddenSelectedRecordId").val();
    //ToastMessage("RefreshPropertyGrid: " + SelectedTable + " / " + SelectedRecordId);
    var SelectedCellTable = $("#HiddenSelectedCellTableId").val();
    var SelectedCellColumnId = $("#HiddenSelectedCellColumnId").val();

    //console.log("RefreshPropertyGridViewFromHiddenSelection: " + SelectedTable + ", " + SelectedRecordId);

    // Fill with partial view from server
    AjaxRefreshPropertyGridView(divElement, "OBJECT", SelectedDataType, SelectedTable, SelectedRecordId, SelectedCellTable, SelectedCellColumnId, ""/*PropertyValuesJsonString*/);
    AddPropertiesGridToContentArray(SelectedDataType, SelectedTable, SelectedRecordId, SelectedCellTable, SelectedCellColumnId);
}







var LastRefreshPropertyGridMs = new Date();
var LastRefreshPropertyGridContentType = null;
var LastRefreshPropertyGridObjectTable = null;
var LastRefreshPropertyGridObjectRecordId = null;

/**
 * Fill the div element with a partial view from server
 * Use object values to fetch the correct view type
 * @param {any} divElement
 * @param {any} ObjectDataType
 * @param {any} ObjectTable
 * @param {any} ObjectRecordId
 */
function AjaxRefreshPropertyGridView(divElement, PropertyType, ObjectDataType, ObjectTable, ObjectRecordId, SelectedCellTable, SelectedCellColumnId, PropertyValuesJsonString) {

    if (!divElement || divElement.length == 0) {
        console.log("RefreshPropertyGridView div does not exist!");
        return;
    }

    //console.log("AjaxGetPropertyGridPartialView: " + ObjectTable + ", " + ObjectRecordId);

    var DivId = divElement.attr('id');
    var bIsEditRecordDialog = (DivId == "igDialogEditRecordPropertiesDiv" && PropertyType != "VIEWSETTINGS");
    
    // Refresh edit dialog if it is open
    // This is an appalling hack. There must be a better way to refresh properties for the active oject
    if (bIsEditRecordDialog) {
        // AjaxRefreshPropertyGridView($("#igDialogEditRecordPropertiesDiv"), "OBJECT", LastEditRecordObjectDataType, LastEditRecordObjectTable, LastEditRecordObjectRecordId, LastEditRecordSelectedCellTable, LastEditRecordSelectedCellColumnId, ""/*PropertyValuesJsonString*/);
        PropertyType = "OBJECT";
        ObjectDataType = LastEditRecordObjectDataType;
        ObjectTable = LastEditRecordObjectTable;
        ObjectRecordId = LastEditRecordObjectRecordId;
        SelectedCellTable = LastEditRecordSelectedCellTable;
        SelectedCellColumnId = LastEditRecordSelectedCellColumnId;
        PropertyValuesJsonString = "";
    }
    // OLD hack to do the same thing as above. Commented out on 6/24/2024 as countdown progress bar was added to properties grid
    //if (!bIsEditRecordDialog && IsEditRecordDialogOpen()) {
    //    CheckRefreshEditRecordDialog();
    //    //console.log("AjaxGetPropertyGridPartialView: Exit early because IsEditRecordDialogOpen ");
    //    return;
    //}

    // Gets in the way of the properties panel
    if (bSmallSizeApp)
        CloseGridEditPopupDialog();

    // These parameters tell the property grid what to display
    // Examples:
    //          stdata.BaseDataSet
    //          wipdata.wipitem
    //          radata.raitem
    if (!ObjectRecordId)
        return;

    var ContentType = GetSelectedContentType();
    var FilterJsonString = GetSelectedContentPaneFilterJsonString();

    // Save values as last time?
    // Repeating refresh? Annoying!
    var bSameValues = (LastRefreshPropertyGridContentType == ContentType && LastRefreshPropertyGridObjectTable == ObjectTable && LastRefreshPropertyGridObjectRecordId == ObjectRecordId);
    if (bSameValues) {
        var Now = new Date();
        var millisecondsSinceLast = Now.getTime() - LastRefreshPropertyGridMs.getTime();
        if (millisecondsSinceLast < 300) {
            //console.log("AjaxGetPropertyGridPartialView: Same values: Less than 300ms " + LastRefreshPropertyGridMs.getTime() + ", " + millisecondsSinceLast + ObjectTable + ", " + ObjectRecordId);
            return;
        }
    }

    // Remember, to prevent annoying flicker when repeatedly refreshing
    if (!bIsEditRecordDialog && IsEditRecordDialogOpen())
        LastRefreshPropertyGridMs = new Date();
    LastRefreshPropertyGridContentType = ContentType;
    LastRefreshPropertyGridObjectTable = ObjectTable;
    LastRefreshPropertyGridObjectRecordId = ObjectRecordId;

    ResetSessionTimeoutTimer();

    //ToastError("Refresh Property Grid", ContentType);
    //console.log("AjaxRefreshPropertyGridView: " + ObjectTable + ", " + ObjectRecordId + ", Stack: " + Error().stack);
    //console.log("AjaxRefreshPropertyGridView: " + ObjectTable + ", " + ObjectRecordId);

    if (ObjectDataType && ObjectDataType.startsWith("QB"))
        ContentType = ObjectDataType;

    //console.log("AjaxGetPropertyGridPartialView: " + ObjectTable + ", " + ObjectRecordId);

    var params = {
        "PropertyType": PropertyType,
        "ContentType": ContentType,
        "SelectedDataType": ObjectDataType,
        "SelectedTable": ObjectTable,
        "SelectedRecordId": ObjectRecordId,
        "SelectedCellTable": SelectedCellTable,
        "SelectedCellColumnId": SelectedCellColumnId,
        "PropertyValuesJsonString": PropertyValuesJsonString,
        "FilterJsonString": FilterJsonString
    };

    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetPropertyGridPartialView/",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json", /*type of data sent to server*/
    }).done(function (data) {

        // Fill new HTML partial view
        // The ~250ms white flash on refresh is Infragistics grid initialization, not a DOM-clear
        // issue. IG builds headers, rows, and scrollbars in async phases after .html() returns;
        // the white background is visible until rows are drawn. Fixing it properly requires hooking
        // into IG's rendered event or setting a background-color on the container to match grid rows.
        //
        // Option A: visibility:hidden + rAF — eliminates the ~16ms DOM-clear blank frame but does
        // NOT help with the IG initialization flash. Reverted after testing.
        // Option B: animate opacity out → swap → wait 300ms for IG init → animate opacity in.
        // Eliminates the flash entirely; tradeoff is ~550ms added per refresh cycle.
        // To try an option: comment out the active lines and uncomment another option's lines.
        //$(divElement).html(data);                                                 // original

        var $div = $(divElement);                                                   // Option A
        $div.css('visibility', 'hidden');                                           // Option A
        $div.html(data);                                                            // Option A
        requestAnimationFrame(function () { $div.css('visibility', ''); });         // Option A

        //var $div = $(divElement);                                                              // Option B
        //$div.animate({ opacity: 0 }, 100, function () {                                       // Option B
        //    $div.html(data);                                                                   // Option B
        //    setTimeout(function () { $div.animate({ opacity: 1 }, 150); }, 300);              // Option B
        //});                                                                                    // Option B

        // Fire update for other modeless UI elements that might care about record property changes
        setTimeout(function () { OnSelectPropertiesChange(PropertyType, ContentType, ObjectDataType, ObjectTable, ObjectRecordId, SelectedCellTable, SelectedCellColumnId, PropertyValuesJsonString, FilterJsonString); }, 500);
    });
}



function AjaxRefreshSettingsGridView(divElement, ContentType) {

    if (!divElement || divElement.length == 0) {
        console.log("RefreshSettingsGridView div does not exist!");
        return;
    }

    if (!ContentType)
        return;

    // Fill properties with these values
    var SettingsJsonString = GetSelectedContentPaneSettingsJsonString();

    // Setings are just a special form of property
    AjaxRefreshPropertyGridView(divElement, "VIEWSETTINGS", ContentType/*ObjectDataType*/, "SETTINGS"/*ObjectTable*/, "SETTINGS"/*ObjectRecordId*/, ""/*SelectedCellTable*/, ""/*SelectedCellColumnId*/, SettingsJsonString);
}


function RefreshBarcodeDefaultsPropertyGridView() {

    // Fill properties with partial view from server
    AjaxRefreshPropertyGridView($("#"+PropertyGridPartialViewDivId), "BARCODEDEFAULTS", "BarcodeDefaults"/*ObjectDataType*/, "Web Edition"/*ObjectTable*/, "Cookies"/*ObjectRecordId*/, ""/*SelectedCellTable*/, ""/*SelectedCellColumnId*/, ""/*PropertyValuesJsonString*/);
    AddPropertiesGridToContentArray("BarcodeDefaults"/*ObjectDataType*/, "Web Edition"/*ObjectTable*/, "Cookies"/*ObjectRecordId*/, ""/*SelectedCellTable*/, ""/*SelectedCellColumnId*/);
}




var LastAjaxRefreshPartialViewByContentType = new Date();
var LastAjaxRefreshContentType = "";
var LastAjaxRefreshFilterJsonString = "";
var LastAjaxRefreshSettingsJsonString = "";

// Minimum seconds between refreshes per content type; add entries here to throttle new types
var AjaxRefreshThrottleSeconds = { "WIP_GROUP_EMPL": 300, "WIP_GROUP_PROJ": 300 };
var AjaxRefreshThrottleLastCall = {};

//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Refresh a partial view
// Use the div element to refresh
// Example: "divRecordsetGridPartialView"
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
function AjaxRefreshPartialViewByContentType(divElement, contenttype, valuestring) {

    //console.trace();
    //console.log("AjaxRefreshPartialViewByContentType: " + contenttype + ", " + new Date().getTime());

    if (!divElement || divElement.length == 0) {
        console.log("RefreshPartialViewByContentType div does not exist!");
        return;
    }

    if (!contenttype) {
        console.log("RefreshPartialViewByContentType content type not specified!");
        return;
    }

    // Always get these values from cookies
    var layoutstring = LoadSelectedPaneLayoutStringFromCookie(); // "Tasks.[Desc],Project_Property,Category_Property,ProjectTask_Property,Actual_Property";
    var filterjsonstring = LoadSelectedPaneFilterJsonStringFromCookie();
    var settingsjsonstring = LoadSelectedPaneSettingsJsonStringFromCookie();
    //ToastError("Refresh", contenttype);

    // Per-content-type throttle guard
    var throttleMs = (AjaxRefreshThrottleSeconds[contenttype] || 0) * 1000;
    if (throttleMs > 0) {
        var lastThrottleCall = AjaxRefreshThrottleLastCall[contenttype];
        var elapsedMs = lastThrottleCall ? (new Date().getTime() - lastThrottleCall.getTime()) : null;
        //console.log("throttle:", contenttype, "elapsed:", elapsedMs, "limitMs:", throttleMs, "keys:", Object.keys(AjaxRefreshThrottleLastCall));
        if (lastThrottleCall && elapsedMs < throttleMs) {
            //console.log("THROTTLED:", contenttype, elapsedMs + "ms < " + throttleMs + "ms");
            return;
        }
        AjaxRefreshThrottleLastCall[contenttype] = new Date();
    }

    // Was this function called just a few milliseconds ago?
    // If so, get out to prevent annoying flashing
    var Now = new Date();
    var millisecondsSinceLastRefresh = Now.getTime() - LastAjaxRefreshPartialViewByContentType.getTime();
    if (millisecondsSinceLastRefresh < 200) {
        // Return because this was just called a few milliseconds ago
        // Repeated refresh is annoying
        // Same data as last time? That confirms it! Do not refresh again
        if (LastAjaxRefreshContentType === contenttype && LastAjaxRefreshFilterJsonString === filterjsonstring && LastAjaxRefreshSettingsJsonString === settingsjsonstring) {
            //ToastMessage("LastAjaxRefresh", LastAjaxRefreshPartialViewByContentType + ", " + contenttype);
            return;
        }
    }
    LastAjaxRefreshPartialViewByContentType = new Date();
    LastAjaxRefreshContentType = contenttype;
    LastAjaxRefreshFilterJsonString = filterjsonstring;
    LastAjaxRefreshSettingsJsonString = settingsjsonstring;

    // No longer in edit mode
    bIsGridInEditMode = false;


    // Get the items that are selected now
    // These will be reselected after the refresh
    // See CheckSelectGridItemsAfterRebuild()
    var ElementId = $(divElement).attr("id");
    SelectGridItemsAfterRebuild = GetSelectedIdsFromPartialViewDiv(ElementId);
    if (SelectRecordIdAfterRebuild && SelectGridItemsAfterRebuild) {
        SelectGridItemsAfterRebuild.SelectedCellIdKeys = [];
        SelectGridItemsAfterRebuild.SelectedTableIds = [];
        SelectGridItemsAfterRebuild.SelectedRowIds = [];
        SelectGridItemsAfterRebuild.SelectedTableIds.push(SelectTableIdAfterRebuild);
        SelectGridItemsAfterRebuild.SelectedRowIds.push(SelectRecordIdAfterRebuild);
        //console.log("AjaxRefreshPartialViewByContentType: " + SelectTableIdAfterRebuild + ", " + SelectRecordIdAfterRebuild);
    }

    ResetSessionTimeoutTimer();

    var params = {
        "ContentType": contenttype,
        "ValueString": valuestring,
        "LayoutString": layoutstring,
        "FilterJsonString": filterjsonstring,
        "SettingsJsonString": settingsjsonstring
    };

    //console.trace("AjaxGetPartialViewByContentType: " + contenttype);
    $.ajax({
        url: VirtualDirectory + "/Home/AjaxGetPartialViewByContentType/",
        type: "POST",
        data: JSON.stringify(params),
        contentType: "application/json", /*type of data sent to server*/
    }).done(function (data) {

        // The ~250ms white flash on refresh is Infragistics grid initialization, not a DOM-clear
        // issue. IG builds headers, rows, and scrollbars in async phases after .html() returns;
        // the white background is visible until rows are drawn. Fixing it properly requires hooking
        // into IG's rendered event or setting a background-color on the container to match grid rows.
        //
        // Option A: visibility:hidden + rAF — eliminates the ~16ms DOM-clear blank frame but does
        // NOT help with the IG initialization flash. Reverted after testing.
        // Option B: animate opacity out → swap → wait 300ms for IG init → animate opacity in.
        // Eliminates the flash entirely; tradeoff is ~550ms added per refresh cycle.
        // To try an option: comment out the active lines and uncomment another option's lines.
        //$(divElement).html(data);                                                 // original

        FlushGanttDragIfActive();

        var $div = $(divElement);                                                   // Option A
        $div.css('visibility', 'hidden');                                           // Option A
        $div.html(data);                                                            // Option A
        requestAnimationFrame(function () { $div.css('visibility', ''); });         // Option A

        //var $div = $(divElement);                                                              // Option B
        //$div.animate({ opacity: 0 }, 100, function () {                                       // Option B
        //    $div.html(data);                                                                   // Option B
        //    setTimeout(function () { $div.animate({ opacity: 1 }, 150); }, 300);              // Option B
        //});                                                                                    // Option B
        //console.log("RefreshPartialViewByContentType: div id: " + $(divElement).attr('id') + ", contenttype: " + contenttype);
    });
}



//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Refresh a partial view
// Use the div element to refresh
// Example: "divRecordsetGridPartialView"
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
function AjaxRefreshPartialView(divElement, controllermethodname) {

    var ContentType = GetSelectedContentType();

    ResetSessionTimeoutTimer();

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

    $.ajax({
        data: JSON.stringify(params),
        contentType: "application/json", /*type of data sent to server*/
        type: "POST",
        url: VirtualDirectory + "/Home/" + controllermethodname + "/"
    }).done(function (data) {
        // IG keeps a global widget registry keyed by DOM ID.
        // Removing the element via.html() does not clean it up. 
        // Reinitializing the same ID throws "Runtime changes are not allowed for the following option: bindings". 
        // Destroy any igTree in the pane before replacing the HTML.
        try { $(divElement).find('.ui-igtree').igTree('destroy'); } catch (e) { }

        // The ~250ms white flash on refresh is Infragistics grid initialization, not a DOM-clear
        // issue. IG builds headers, rows, and scrollbars in async phases after .html() returns;
        // the white background is visible until rows are drawn. Fixing it properly requires hooking
        // into IG's rendered event or setting a background-color on the container to match grid rows.
        //
        // Option A: visibility:hidden + rAF — eliminates the ~16ms DOM-clear blank frame but does
        // NOT help with the IG initialization flash. Reverted after testing.
        // Option B: animate opacity out → swap → wait 300ms for IG init → animate opacity in.
        // Eliminates the flash entirely; tradeoff is ~550ms added per refresh cycle.
        // To try an option: comment out the active lines and uncomment another option's lines.
        //$(divElement).html(data);                                                 // original

        FlushGanttDragIfActive();

        var $div = $(divElement);                                                   // Option A
        $div.css('visibility', 'hidden');                                           // Option A
        $div.html(data);                                                            // Option A
        requestAnimationFrame(function () { $div.css('visibility', ''); });         // Option A

        //var $div = $(divElement);                                                              // Option B
        //$div.animate({ opacity: 0 }, 100, function () {                                       // Option B
        //    $div.html(data);                                                                   // Option B
        //    setTimeout(function () { $div.animate({ opacity: 1 }, 150); }, 300);              // Option B
        //});                                                                                    // Option B
    });
}



function SelectHomeAllViews() {
    $('#HomeAllViewsButton').trigger('click');
}


function RefreshSelectedContent() {
    RefreshActiveDockPane();
}




//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
//\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\////\\//
// Defer refresh so users have time to enter hours into timesheet
// This allows users time to enter hours into timesheet cells without constant refreshes
// When all changes are made, the page refreshes (several seconds later)

var AppDeferTimeoutID = 0;
var PrtDeferTimeoutID = 0;
var AppCirclebarObject = null;
var PrtCirclebarObject = null;

function DeferRefreshSelectedContent(seconds, callbackfunction) {

    if (!seconds || seconds == null || seconds <= 0)
        seconds = GetDeferRefreshSecondsFromCookie();
    if (seconds <= 0) {
        RefreshSelectedContent();
        return;
    }

    //console.log("DeferRefreshSelectedContent: " + seconds);

    // If you don't clear the timeout below, you get repeated refreshes every time you enter a grid value
    // Example: Type repeatedly into timesheet cells, and you will get repeated refreshes that are very annoying
    // So, you must clear this timeout for each timesheet entry
    if (AppDeferTimeoutID > 0)
        clearTimeout(AppDeferTimeoutID);
    AppDeferTimeoutID = 0;

    // Add the progress bar
    AddAppCircleProgressBarElements();

    // Remember the page to refresh (in case the user clicks another tab and changes to a different page)
    var RefreshSlotDivId = $('input[id="HiddenSelectedContentSlotDivId"]').val();

    // Set a timer to refresh the page
    AppDeferTimeoutID = setTimeout(function () {

        //console.log("DeferRefreshSelectedContent timeout");

        // Hide the progress bar
        $('#AppCircleProgressBar').css('display', 'none');

        // Refreshing every time an "Edit" dialog is open is disruptive
        var bIsAnyModalDialogOpen = IsAnyModalDialogOpen();
        if (!bIsAnyModalDialogOpen) {
            // Refresh now!
            RefreshSelectedContent();
        }

        // Callback when the content is refreshed
        if (callbackfunction) {
            setTimeout(function () { callbackfunction(); }, 20);
        }

    }, (seconds * 1000));

    //console.log("DeferRefreshSelectedContent setTimeout ID: " + AppDeferTimeoutID);

    // Start circle progress bar to show countdown
    if (AppCirclebarObject)
        AppCirclebarObject.clearCircle();
    $('#AppCircleProgressBar').css('display', 'block');
    AppCirclebarObject = new Circlebar({ element: "#AppCircleProgressBar", startValue: 0, maxValue: seconds, skin: "white", });
}


function AddAppCircleProgressBarElements() {

    var AppCircleProgressBarObject = $('#AppCircleProgressBar');
    if (!AppCircleProgressBarObject || AppCircleProgressBarObject.length == 0)
        $("#AppProgressBarDiv").append('<div id="AppCircleProgressBar"class="circlebar" data-circle-dialWidth=2 data-circle-size="24px" data-circle-fontSize="7pt" style="width:24px;height:24px; display:none;" onclick="OnConfigureDeferRefresh()"><div class="loader-bg"><div class="text" style=""></div></div></div>');
}


/**
 * Get the actual circle progress bar element object in the property grid
 * @returns
 */
function GetPrtCircleProgressObject() {

    var ActivePropertyGridPartialViewDivObject = $('#' + ActivePropertyGridPartialViewDivId);
    if (!ActivePropertyGridPartialViewDivObject || ActivePropertyGridPartialViewDivObject.length == 0)
        return;

//    var PrtCircleProgressBarObject = $('#PrtCircleProgressBar');
    var PrtCircleProgressBarObject = ActivePropertyGridPartialViewDivObject.find("[id='PrtCircleProgressBar']");
    if (PrtCircleProgressBarObject && PrtCircleProgressBarObject.length > 0)
        return PrtCircleProgressBarObject;
    return null;
}


/**
 * Place the circle progress bar inside this div (in the property grid)
 * This is a placeholder
 * @returns
 */
function GetPrtProgressBarDivObject() {

    var ActivePropertyGridPartialViewDivObject = $('#' + ActivePropertyGridPartialViewDivId);
    if (!ActivePropertyGridPartialViewDivObject || ActivePropertyGridPartialViewDivObject.length == 0)
        return null;

    //    var PrtCircleProgressBarObject = $('#PrtCircleProgressBar');
    var PrtProgressBarDiv = ActivePropertyGridPartialViewDivObject.find("[id='PrtProgressBarDiv']");
    if (PrtProgressBarDiv && PrtProgressBarDiv.length > 0)
        return PrtProgressBarDiv;
    return null;
}

/**
 * Add the circle progress bar to the property grid if it's not already there
 * There should be a placeholder div to put it into
 * @returns
 */
function AddPrtCircleProgressBarElements() {

    // Already added?
    var PrtProgressBarObject = GetPrtCircleProgressObject();
    if (PrtProgressBarObject && PrtProgressBarObject.length > 0)
        return;

    // Find div it should be palced in
    var PrtProgressBarDiv = GetPrtProgressBarDivObject();
    if (PrtProgressBarDiv && PrtProgressBarDiv.length > 0) {
        PrtProgressBarDiv.append('<button class="toolbarbutton24" data-image="stdata.images.enabled.symbol-update@16px.png" data-image-size="32" onclick="CancelPropertiesCountdownAndRefresh()" title="Refresh"></button>');
        PrtProgressBarDiv.append('<div id="PrtCircleProgressBar"class="circlebar" data-circle-dialWidth=2 data-circle-size="24px" data-circle-fontSize="7pt" style="width:24px;height:24px; display:none;" onclick="OnConfigureDeferRefresh()"><div class="loader-bg"><div class="text" style=""></div></div></div>');

        // Load images
        SetupElementImagesInDivByParent(PrtProgressBarDiv);
    }
}


function OnConfigureDeferRefresh() {
    var seconds = GetDeferRefreshSecondsFromCookie();
    PopupPromptForValueBox("Deferred Refresh", "Number of seconds to defer refreshes", seconds, OnConfigureDeferRefreshResults);
}

function OnConfigureDeferRefreshResults(prompt) {

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

    // Good value?
    if (!$.isNumeric(prompt.sValue)) {
        PopupErrorMessage("Deferred Refresh", "Enter the number seconds, or 0 to turn off deferred refresh");
        return;
    }

    var seconds = Number(prompt.sValue);
    SetDeferRefreshSecondsCookie(seconds);
    //ToastMessage("OnConfigureDeferRefreshResults", prompt.sValue);
}



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

/**
 * A record property panel has changed
 * This normally occurs when a user clicks a row in a grid
 * @param {any} PropertyType
 * @param {any} ContentType
 * @param {any} ObjectDataType
 * @param {any} ObjectTable
 * @param {any} ObjectRecordId
 * @param {any} SelectedCellTable
 * @param {any} SelectedCellColumnId
 * @param {any} PropertyValuesJsonString
 * @param {any} FilterJsonString
 */
function OnSelectPropertiesChange(PropertyType, ContentType, ObjectDataType, ObjectTable, ObjectRecordId, SelectedCellTable, SelectedCellColumnId, PropertyValuesJsonString, FilterJsonString) {

    if (ObjectTable == "SETTINGS")
        return;

    // These places care about selecting new objects
    // Ai chat window responds to clicking projects by offering to analyze them
    OnAiChatSelectPropertiesChange(PropertyType, ContentType, ObjectDataType, ObjectTable, ObjectRecordId, SelectedCellTable, SelectedCellColumnId, PropertyValuesJsonString, FilterJsonString);
}





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



