"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var sp_core_library_1 = require("@microsoft/sp-core-library");
var sp_diagnostics_1 = require("@microsoft/sp-diagnostics");
var sp_loader_1 = require("@microsoft/sp-loader");
var sp_page_context_1 = require("@microsoft/sp-page-context");
var sp_telemetry_1 = require("@ms/sp-telemetry");
var ApplicationManager_1 = tslib_1.__importDefault(require("../ApplicationManager"));
var Killswitches_1 = require("../common/Killswitches");
var ApplicationCustomizerLoader_1 = tslib_1.__importDefault(require("../extensibility/ApplicationCustomizerLoader"));
var SearchQueryManager_1 = tslib_1.__importDefault(require("../extensibility/SearchQueryManager"));
var Navigator_1 = tslib_1.__importDefault(require("./Navigator"));
/**
 * It orchestrates all different steps to navigate to an SPFx application.
 *
 * This includes updating the Page Context, loading the application customizers, initializing the application, etc.
 */
var NavigationOrchestrator = /** @class */ (function () {
    /**
     * Creates a NavigationOrchestrator.
     *
     * @param serviceScope - Root service scope
     * @param applicationManager - Depending on the bootstrapping sequence, application manager is
     *                             injected or created inside.
     */
    function NavigationOrchestrator(serviceScope, applicationManager, navigator) {
        this._numAppsInitializedInSession = 0;
        sp_core_library_1.Validate.isNotNullOrUndefined(serviceScope, 'serviceScope');
        this._serviceScope = serviceScope;
        this._applicationManager = applicationManager || new ApplicationManager_1.default(serviceScope, navigator);
        this._pageContext = serviceScope.consume(sp_page_context_1.PageContext.serviceKey);
        this._searchQueryManager = serviceScope.consume(SearchQueryManager_1.default.serviceKey);
        this._applicationCustomizerLoader = new ApplicationCustomizerLoader_1.default(serviceScope);
    }
    /**
     * Does all the operation to navigate to a new preloaded data.
     *
     * @remarks
     * It assumes the preloaded data has already been validated. Not null, with a spPageContextInfo and an application id.
     */
    NavigationOrchestrator.prototype.navigate = function (preloadedData) {
        var _this = this;
        var _a;
        var currentAppId = this._applicationManager.currentApplicationId;
        var appLoaded = !currentAppId.equals(sp_core_library_1.Guid.empty);
        var isSameApp = currentAppId.equals(sp_core_library_1.Guid.tryParse(preloadedData.clientSideApplicationId) || sp_core_library_1.Guid.empty);
        /**
         * Safe net for navigations to doclib/list:
         * If the former and current app are sp-list-host, then it means that we
         * are probably entering into an infinite loop of ListHost.aspx.
         * In such a case, throw an error, and do a full-page load.
         */
        if (isSameApp &&
            appLoaded &&
            currentAppId.equals(sp_core_library_1.Guid.tryParse(NavigationOrchestrator.spListHostComponentId))) {
            var qosMonitor = new sp_telemetry_1._QosMonitor('ListHostBlankPage');
            qosMonitor.writeSuccess();
            throw new Error('SP-List-Host App: Navigation within the listhost app is not supported.');
        }
        var isAppIdSameOrEmpty = isSameApp || !appLoaded;
        var unsupportedReason = this._isNavigationSupportedWithReason(preloadedData, this._pageContext, isAppIdSameOrEmpty);
        if (unsupportedReason !== undefined) {
            return Promise.resolve({
                preloadedData: preloadedData,
                application: undefined,
                operation: 'Unsupported',
                unsupportedReason: unsupportedReason
            });
        }
        if (!Killswitches_1.Killswitches.isClearEventQueueKSActivated()) {
            Navigator_1.default.clearNavigatedEventQueue();
        }
        this._fixPreloadedDataItem(preloadedData);
        var isCrossSite = this._isCrossSite(preloadedData, this._pageContext);
        // TODO: demyren: VSO:428542 - clean up when moving to new PageContext
        var pageContextData = sp_page_context_1.SharePointPageContextDataProvider._createPageContextData(preloadedData.spPageContextInfo);
        if (!Killswitches_1.Killswitches.AddPageUniqueIdToPageContextKillSwitchActivated() && pageContextData.listItem) {
            pageContextData.listItem.uniqueId = (_a = preloadedData.item) === null || _a === void 0 ? void 0 : _a.UniqueId;
        }
        this._pageContext.initialize(pageContextData, preloadedData.spPageContextInfo);
        if (!sp_core_library_1._SPKillSwitch.isActivated('153edef1-9c5b-4ad1-aa5f-a9c53071e0fa' /* '08/28/2020', 'Skip server manifests on sw-powered pages' */) &&
            window['__spfxMark'] // tslint:disable-line:no-string-literal
        ) {
            sp_loader_1._ManifestStore.instance.registerManifests(preloadedData.manifests, false);
        }
        else {
            sp_loader_1._ManifestStore.instance.replaceManifests(preloadedData.manifests);
        }
        if (isCrossSite &&
            !ApplicationManager_1.default._isChromelessApplication(preloadedData.clientSideApplicationId) &&
            appLoaded &&
            isSameApp) {
            this._applicationManager.currentApplication._loadTheme();
        }
        this._updateTelemetry(preloadedData);
        // Discouraging application developers to use spPageContextInfo and instead to use the Page Context API.
        preloadedData.spPageContextInfo = undefined;
        sp_core_library_1.Session._changePage();
        if (preloadedData.clientSideApplicationId) {
            sp_core_library_1.Session._setClientSideApplicationId(preloadedData.clientSideApplicationId);
        }
        if (NavigationOrchestrator.spListHostComponentId !== preloadedData.clientSideApplicationId) {
            Navigator_1.default.raiseNavigatedEvent();
        }
        // If it's the same application, just return with the result.
        if (isSameApp) {
            this._initializeSearchQuery(preloadedData);
            // The application doesn't change, but the preloaded data has. We need to re-load the app customizers.
            // There is an already loaded application, so there is no need to initialize any chromes before the app customizers are re-loaded
            this._loadApplicationCustomizers(preloadedData);
            return Promise.resolve({
                preloadedData: preloadedData,
                application: this._applicationManager.currentApplication,
                operation: 'UpdateContext',
                isXSite: isCrossSite
            });
        }
        sp_telemetry_1._PerformanceLogger.markCrossAppNavigationStart();
        return this._applicationManager.startApplication(preloadedData).then(function (application) {
            _this._numAppsInitializedInSession++;
            _this._initializeSearchQuery(preloadedData);
            // Load app customizers after the application has rendered to )ensure placeholders have been set up.
            _this._loadApplicationCustomizers(preloadedData);
            if (NavigationOrchestrator.spListHostComponentId === preloadedData.clientSideApplicationId) {
                /* tslint:disable-next-line:no-string-literal */
                window['moduleLoaderPromise'] = Promise.resolve(application);
            }
            return Promise.resolve({
                preloadedData: preloadedData,
                application: application,
                operation: 'LoadApplication',
                isXSite: isCrossSite
            });
        });
    };
    /**
     * Loads the application customizers for the current page.
     * @param preloadedData - Preloaded data for the current page.
     *
     * @internal
     */
    NavigationOrchestrator.prototype._loadApplicationCustomizers = function (preloadedData) {
        if (this._appSupportsExtensions(preloadedData)) {
            sp_diagnostics_1._TraceLogger.logVerbose(NavigationOrchestrator._logSource, 'Loading application customizers');
            return this._applicationCustomizerLoader.loadExtensions(preloadedData.customActions);
        }
        else {
            sp_diagnostics_1._TraceLogger.logVerbose(NavigationOrchestrator._logSource, 'Application Customizer is not supported for classic pages and workbench.');
            return Promise.resolve();
        }
    };
    /**
     * Every time the URL gets updated (and there is a navigation) the search query needs to be updated
     * in the page context.
     * It's done in an async way to include loading SearchQueryModifier extensions when necessary.
     *
     * Setting up the search query is disabled for applications that don't have this scenario.
     * If that situation changes (like SPHome supporting search scenario) the check will need to be revisited.
     */
    NavigationOrchestrator.prototype._initializeSearchQuery = function (preloadedData) {
        var _this = this;
        if (preloadedData.clientSideApplicationId !== NavigationOrchestrator.classicPagesComponentId &&
            preloadedData.clientSideApplicationId !== NavigationOrchestrator.workbenchComponentId &&
            preloadedData.clientSideApplicationId !== NavigationOrchestrator.spHomeComponentId) {
            return this._searchQueryManager
                .initialize(preloadedData, function (serviceScope, searchQuery) {
                if (_this._applicationManager.currentApplicationId !== sp_core_library_1.Guid.empty) {
                    var pageChromeProvider = _this._applicationManager.currentApplication._getPageChromeProvider();
                    pageChromeProvider === null || pageChromeProvider === void 0 ? void 0 : pageChromeProvider.updateSearchBoxText(serviceScope, searchQuery);
                }
            })
                .then(function () { return _this._searchQueryManager.getSearchData(); })
                .then(function (searchData) {
                if (!sp_core_library_1._SPKillSwitch.isActivated('c55b73f2-1ec7-453a-a41e-e21131206fd1' /* '03/03/2021', 'Add scope to search dynamic data' */) &&
                    (sp_core_library_1._SPFlight.isEnabled(1534 /*CSISpoScopeControl*/) ||
                        sp_core_library_1._SPExperiment.getVariantAndLogExposure(90097 /*CSISpoScopeControlExperiment*/) === 1)) {
                    _this._pageContext._setSearchData(searchData);
                }
                else {
                    _this._pageContext._setSearchQuery(searchData.searchQuery);
                }
            });
        }
        return Promise.resolve();
    };
    NavigationOrchestrator.prototype._appSupportsExtensions = function (preloadedData) {
        if (preloadedData.clientSideApplicationId !== NavigationOrchestrator.classicPagesComponentId) {
            return true;
        }
        return false;
    };
    NavigationOrchestrator.prototype._updateTelemetry = function (preloadedData) {
        var _a, _b, _c, _d, _e, _f;
        // This will eventually be removed when the migration to Diagnostics is complete
        var manifestAlias = preloadedData && preloadedData.manifests && preloadedData.manifests.length > 0
            ? preloadedData.manifests[0].alias
            : '';
        var contextInfo;
        var _g = this._pageContext.legacyPageContext, isHubSite = _g.isHubSite, webTemplate = _g.webTemplate, hubSiteId = _g.hubSiteId;
        var pageType;
        var promotedState;
        var pageId;
        if (preloadedData && preloadedData.item) {
            // tslint:disable-next-line:no-string-literal
            pageType = preloadedData.item['PageLayoutType'];
            // tslint:disable-next-line:no-string-literal
            promotedState = preloadedData.item['PromotedState'];
            // tslint:disable-next-line:no-string-literal
            pageId = preloadedData.item['UniqueId'];
        }
        else if (!Killswitches_1.Killswitches.isPageTypeForLayoutsKSActivated()) {
            // Update page type if going to a system _layouts page or cross-app otherwise
            var layoutsPrefix = '/_layouts/15/';
            var href = window.location.href;
            var normalizedPath = href.toLowerCase();
            var layoutsIndex = normalizedPath.indexOf(layoutsPrefix);
            var nextAppType = void 0;
            if (layoutsIndex > -1) {
                var aspxSuffix = '.aspx';
                var nameEndIndex = normalizedPath.indexOf(aspxSuffix);
                var systemPageName = href.substring(layoutsIndex + layoutsPrefix.length, nameEndIndex > -1 ? nameEndIndex : undefined);
                nextAppType = "SystemLayouts_" + systemPageName;
            }
            else {
                nextAppType = "CrossApp";
            }
            // Not adding to enum as these are not actual SpPage types but
            // represent cross-app navigation.
            pageType = nextAppType;
        }
        contextInfo = {
            pageId: pageId,
            isHubSite: isHubSite,
            webTemplate: webTemplate,
            pageType: pageType,
            promotedState: promotedState,
            hubSiteId: isHubSite ? hubSiteId : undefined
        };
        var workloadName = !Killswitches_1.Killswitches.isChangeWorkloadForTeamsWorkBenchKSActivated() &&
            window.location.href.indexOf('/_layouts/15/TeamsWorkBench.aspx') > -1
            ? 'TeamsWorkBench'
            : manifestAlias;
        var isAriaTokenKSActivated = sp_core_library_1._SPKillSwitch.isActivated('4ece3b19-59df-4f7d-a576-60c7c2f0f088'
        /* '01/19/2022', 'Use Aria Tokens for sp-list-host app' */
        );
        if (!isAriaTokenKSActivated) {
            sp_telemetry_1._Telemetry.updateSettings({
                siteId: this._pageContext.site.id.toString(),
                webId: this._pageContext.web.id.toString(),
                listId: ((_a = this._pageContext.list) === null || _a === void 0 ? void 0 : _a.id.toString()) || '',
                listItemUniqueId: ((_b = this._pageContext.listItem) === null || _b === void 0 ? void 0 : _b.id.toString()) || '',
                correlationId: this._pageContext.site.correlationId.toString(),
                clientSideApplicationId: preloadedData.clientSideApplicationId
            }, this._pageContext.legacyPageContext, workloadName);
        }
        else {
            sp_telemetry_1._Telemetry.updateSettings({
                siteId: this._pageContext.site.id.toString(),
                webId: this._pageContext.web.id.toString(),
                listId: ((_c = this._pageContext.list) === null || _c === void 0 ? void 0 : _c.id.toString()) || '',
                listItemUniqueId: ((_d = this._pageContext.listItem) === null || _d === void 0 ? void 0 : _d.id.toString()) || '',
                correlationId: this._pageContext.site.correlationId.toString()
            }, this._pageContext.legacyPageContext, workloadName);
        }
        sp_diagnostics_1._Diagnostics.updateSettings({
            siteId: this._pageContext.site.id.toString(),
            webId: this._pageContext.web.id.toString(),
            listId: ((_e = this._pageContext.list) === null || _e === void 0 ? void 0 : _e.id.toString()) || '',
            listItemUniqueId: ((_f = this._pageContext.listItem) === null || _f === void 0 ? void 0 : _f.id.toString()) || '',
            correlationId: this._pageContext.site.correlationId.toString(),
            contextInfo: contextInfo
        });
    };
    /**
     * Returns true if a navigator from the page context to the new preloaded data is a cross-site navigation.
     * This operation needs to happen before updating the page context with the new preloaded data.
     */
    NavigationOrchestrator.prototype._isCrossSite = function (preloadedData, pageContext) {
        if (!pageContext.isInitialized) {
            // This happens in the first load.
            return false;
        }
        return (!sp_core_library_1.Guid.parse(preloadedData.spPageContextInfo.webId).equals(pageContext.web.id) ||
            !sp_core_library_1.Guid.parse(preloadedData.spPageContextInfo.siteId).equals(pageContext.site.id));
    };
    NavigationOrchestrator.prototype._fixPreloadedDataItem = function (preloadedData) {
        var INVALID_PAGE_ITEM_ID = -1;
        // Use the preloadedData's item id if the spPageContextInfo item id is unavailable
        // The workbench can provide a list item via query string which will not be reflected in the
        // spPageContextInfo variable.
        if (preloadedData.spPageContextInfo.pageItemId === INVALID_PAGE_ITEM_ID &&
            preloadedData.item &&
            preloadedData.item.ID !== INVALID_PAGE_ITEM_ID) {
            preloadedData.spPageContextInfo.pageItemId = preloadedData.item.ID;
        }
        return preloadedData;
    };
    /**
     * Determines whether inplace navigation is supported.
     *
     * @param preloadedData - Application preloaded data
     * @param pageContext - Application context
     * @param isSameAppId - Whether the navigation is happening within the same app
     *
     * @returns True if navigation is supported else false
     */
    NavigationOrchestrator.prototype._isNavigationSupportedWithReason = function (preloadedData, pageContext, isSameAppId) {
        var isDifferentLocale = pageContext.isInitialized &&
            pageContext.cultureInfo.currentUICultureName !== preloadedData.spPageContextInfo.currentUICultureName;
        // Navigation is supported if the target locale is the same and the target application id is same as current
        // application Id or the number of in-place navigations are within the threshold.
        if (isDifferentLocale) {
            return 'LocaleChange';
        }
        if (!isSameAppId &&
            this._numAppsInitializedInSession > NavigationOrchestrator.maxSupportedAppsInSession) {
            return 'TransitionsExceeded';
        }
        return undefined;
    };
    NavigationOrchestrator.classicPagesComponentId = 'eb4b666b-5c29-4dad-9a99-23613f21a2b7';
    NavigationOrchestrator.workbenchComponentId = '8be81a5c-af38-4bb2-af97-afa3b64dfbed';
    NavigationOrchestrator.spHomeComponentId = '1f019ae1-2de1-4f44-b723-00a6ec1d7445';
    NavigationOrchestrator.spListHostComponentId = '9f012051-e030-4487-9eb7-3365d03be182';
    NavigationOrchestrator._logSource = sp_diagnostics_1._LogSource.create('NavigationOrchestrator');
    NavigationOrchestrator.maxSupportedAppsInSession = 15;
    return NavigationOrchestrator;
}());
exports.default = NavigationOrchestrator;
//# sourceMappingURL=NavigationOrchestrator.js.map