{# @copyright   Copyright (C) 2010-2024 Combodo SAS #}
{# @license     http://opensource.org/licenses/AGPL-3.0 #}
{% apply spaceless %}
    {% set sId = oLayout.GetId() | sanitize(constant('utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME')) %}
    {% set bHasOnInitOrOnDomReadyScripts = aPage.aJsInlineOnInit is not empty or aPage.aJsInlineOnDomReady is not empty %}
    {% if bEscapeContent %}
        {{ render_block(oLayout, {aPage: aPage})|escape }}
    {% else %}
        {{ render_block(oLayout, {aPage: aPage}) }}
    {% endif %}

    {% block iboPageJsInlineEarly %}
        {% for sJsInline in aPage.aJsInlineEarly %}
            {# We put each scripts in a dedicated script tag to prevent massive failure if 1 script is broken (eg. missing semi-colon or non closed multi-line comment) #}
            <script type="text/javascript">
            {{ sJsInline|raw }}
            </script>
        {% endfor %}
    {% endblock %}

    {% block iboPageJsInlineLive %}
        {% for sJsInline in aPage.aJsInlineLive %}
            {# We put each scripts in a dedicated script tag to prevent massive failure if 1 script is broken (eg. missing semi-colon or non closed multi-line comment) #}
            <script type="text/javascript">
                {{ sJsInline|raw }}
            </script>
        {% endfor %}
    {% endblock %}

    {% if bHasOnInitOrOnDomReadyScripts %}
        <script type="text/javascript">
            let fOnJsFilesLoaded{{ sId }} = function (fResolve) {
                {% for sJsInline in aPage.aJsInlineOnInit %}
                {{ sJsInline|raw }}
                {% endfor %}
    
                {% for sJsInline in aPage.aJsInlineOnDomReady %}
                {{ sJsInline|raw }}
                {% endfor %}
                fResolve();
            }
        </script>
    {% endif %}
    
    {% set sPromiseId = aPage.sPromiseId %}
	{% if aPage.aJsFiles is not empty %}
        {% block iboPageJsFiles %}
            <script type="text/javascript">
                {% if bHasOnInitOrOnDomReadyScripts == false %}
                // Define a dummy empty callback if there's no script to execute
                let fOnJsFilesLoaded{{ sId }} = function (fResolve) {
                    fResolve();
                }
                {% endif %}
                
                window['{{ sPromiseId }}'] = new Promise(function (fAllJsFilesResolve, fAllJsFilesReject) {
                    /**
                     * @type {Array} aJsFilesToLoad Files required by the current AjaxPage
                     *
                     * For each file:
                     * - "id": Used as an identifier to check if file is already being handled
                     * - "url" is the URL that will be used for loading. It should include any relevant query args, including the cache buster
                     *
                     * ```
                     * [
                     *  {"id": "https://itop/js/foo.js", "url": "https://itop/js/foo.js?cache_buster=123},
                     *  {"id": "https://itop/js/bar.js", "url": "https://itop/js/bar.js?a=b&cache_buster=123"},
                     *  ...
                     * ]
                     * ```
                     */
                    
                    // If these constants aren't defined by the main page, define them (global) ourselves
                    if (typeof aLoadedJsFilesRegister === "undefined") {
                        Object.defineProperty(window, "aLoadedJsFilesRegister", {
                            value: new Map(),
                            writable: false,
                            configurable: false,
                            enumerable: true
                        });
                    }      
                    
                    if (typeof aLoadedJsFilesResolveCallbacks === "undefined") {
                        Object.defineProperty(window, "aLoadedJsFilesResolveCallbacks", {
                            value: new Map(),
                            writable: false,
                            configurable: false,
                            enumerable: true
                        });
                    }
                    
                    let aJsFilesToLoad = [];
                    /**
                     * @type {Array} aJsFilesToLoadByOtherRequests Files required by the current AjaxPage but that are already being handled by another request (done or ongoing)
                     */
                    let aJsFilesToLoadByOtherRequests = [];

                    {% for sJsFile in aPage.aJsFiles %}
                        aJsFilesToLoad.push({
                            "id": "{{ sJsFile|raw }}",
                            "url": "{{ sJsFile|add_itop_version|raw }}"
                        });

                        // If file is already present in the register (see it declaration in WebPage TWIG template), let its original requester load it
                        if (aLoadedJsFilesRegister.has("{{ sJsFile|raw }}") === true) {
                            aJsFilesToLoadByOtherRequests.push("{{ sJsFile|raw }}");
                        }
                        // Otherwise add it to register and initialize corresponding promise
                        else {
                            aLoadedJsFilesRegister.set("{{ sJsFile|raw }}", new Promise(function(fJsFileResolve) {
                                aLoadedJsFilesResolveCallbacks.set("{{ sJsFile|raw }}", fJsFileResolve);
                            }));
                        }
                    {% endfor %}

                    let iCurrentIdx = 0;
                    let iFilesToLoadCount = aJsFilesToLoad.length;
                    if (iFilesToLoadCount > 0)
                    {
                        let fLoadScript{{ sId }} = function () {
                            let sCurrentFileId = aJsFilesToLoad[iCurrentIdx]["id"];
                            let sCurrentFileUrl = aJsFilesToLoad[iCurrentIdx]["url"];

                            /** @type {Promise} oPromise Promise to use once file is loaded */
                            let oPromise = null;
                            // If file is handled by another request, retrieve the existing promise
                            if ($.inArray(sCurrentFileId, aJsFilesToLoadByOtherRequests) !== -1) {
                                oPromise = aLoadedJsFilesRegister.get(sCurrentFileId)
                            }
                            // Otherwise create its own promise to load it
                            else {
                                oPromise = $.when(
                                        $.ajax({
                                            url: sCurrentFileUrl,
                                            dataType: 'script',
                                            cache: true
                                        }),
                                        aLoadedJsFilesResolveCallbacks.get(sCurrentFileId)()
                                );
                            }

                            // Only once file is loaded (by the request or another), proceed to next step
                            oPromise.then(function () {
                                iCurrentIdx++;
                                if (iCurrentIdx !== iFilesToLoadCount)
                                {
                                    fLoadScript{{ sId }}();
                                }
                                else
                                {
                                    fOnJsFilesLoaded{{ sId }}(fAllJsFilesResolve);
                                }
                            });
                        };
                        fLoadScript{{ sId }}();
                    }
                    else
                    {
                        fOnJsFilesLoaded{{ sId }}(fAllJsFilesResolve);
                    }
                });
            </script>
        {% endblock %}
    {% else %}
        {% if bHasOnInitOrOnDomReadyScripts %}
            {% block iboPageJsInlineOnDomReady %}
                <script type="text/javascript">
                    window['{{ sPromiseId }}'] = new Promise(function (fNoJsFileResolve, fNoJsFileReject) {
                        fOnJsFilesLoaded{{ sId }}(fNoJsFileResolve);
                    });
                </script>
            {% endblock %}
        {% endif %}
    {% endif %}

    {% if aDeferredBlocks is not empty %}
        {% for oBlock in aDeferredBlocks %}
            {{ render_block(oBlock, {aPage: aPage})|raw }}
        {% endfor %}
    {% endif %}

    {% if sDeferredContent %}
        <script type="text/javascript">
            $('body').append('{{ sDeferredContent|raw }}');
        </script>
    {% endif %}

    {% block iboPageCssFiles %}
        {% if aPage.aCssFiles is not empty %}
            <script type="text/javascript">
                // If this constant isn't defined by the main page, define it (global) ourselves
                if (typeof aLoadedCssFilesRegister === "undefined") {
                    Object.defineProperty(window, "aLoadedCssFilesRegister", {
                        value: new Map(),
                        writable: false,
                        configurable: false,
                        enumerable: true
                    });
                }

                {% for aCssFileData in aPage.aCssFiles %}
                    // Only if file is NOT already present in the register (see it declaration in WebPage TWIG template), add it to the page and register
                    if (aLoadedCssFilesRegister.has("{{ aCssFileData['link']|raw }}") === false) {
                        $('<link href="{{ aCssFileData['link'] }}" rel="stylesheet">').appendTo('head');
                        aLoadedCssFilesRegister.set("{{ aCssFileData['link']|raw }}", true);
                    }
                {% endfor %}
            </script>
        {% endif %}
    {% endblock %}

    {{ aPage.sCapturedOutput|raw }}

{% endapply %}