/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module UiProvider
 */
import { BeUiEvent, Logger } from "@itwin/core-bentley";
import { UiFramework } from "../UiFramework";
import { createAbstractUiItemsManagerAdapter, createGetPropertyAdapter, } from "./AbstractUiItemsManager";
/** Controls registering of UiItemsProviders and calls the provider's methods when populating different parts of the User Interface.
 * @public
 */
class UiItemsManager {
    /** For use in unit testing
     * @internal
     */
    static useAbstractAdapter(useAbstractAdapter) {
        if (useAbstractAdapter) {
            this._abstractAdapter = createAbstractUiItemsManagerAdapter();
        }
        else {
            this._abstractAdapter = undefined;
        }
    }
    /** For use in unit testing
     * @internal */
    static clearAllProviders() {
        if (this._abstractAdapter)
            return this._abstractAdapter.clearAllProviders();
        UiItemsManager._registeredUiItemsProviders.clear();
    }
    /** Event raised any time a UiProvider is registered or unregistered. */
    static get onUiProviderRegisteredEvent() {
        if (this._abstractAdapter)
            return this._abstractAdapter.onUiProviderRegisteredEvent;
        return this._onUiProviderRegisteredEvent;
    }
    /** Return number of registered UiProvider. */
    static get registeredProviderIds() {
        if (this._abstractAdapter)
            return this._abstractAdapter.registeredProviderIds;
        const ids = [...UiItemsManager._registeredUiItemsProviders.keys()];
        return ids;
    }
    /** Return true if there is any registered UiProvider. */
    static get hasRegisteredProviders() {
        if (this._abstractAdapter)
            return this._abstractAdapter.hasRegisteredProviders;
        return this._registeredUiItemsProviders.size > 0;
    }
    /**
     * Retrieves a previously loaded UiItemsProvider.
     * @param providerId id of the UiItemsProvider to get
     */
    static getUiItemsProvider(providerId) {
        var _a;
        if (this._abstractAdapter)
            return this._abstractAdapter.getUiItemsProvider(providerId);
        return (_a = UiItemsManager._registeredUiItemsProviders.get(providerId)) === null || _a === void 0 ? void 0 : _a.provider;
    }
    static sendRegisteredEvent(args) {
        UiItemsManager.onUiProviderRegisteredEvent.raiseEvent(args);
    }
    /**
     * Registers a UiItemsProvider with the UiItemsManager.
     * @param uiProvider the UI items provider to register.
     * @param overrides the UI items provider to register.
     */
    static register(uiProvider, overrides) {
        var _a;
        if (this._abstractAdapter)
            return this._abstractAdapter.register(uiProvider, overrides);
        const providerId = (_a = overrides === null || overrides === void 0 ? void 0 : overrides.providerId) !== null && _a !== void 0 ? _a : uiProvider.id;
        if (UiItemsManager.getUiItemsProvider(providerId)) {
            Logger.logInfo(UiFramework.loggerCategory(this), `UiItemsProvider (${providerId}) is already loaded`);
        }
        else {
            UiItemsManager._registeredUiItemsProviders.set(providerId, {
                provider: uiProvider,
                overrides,
            });
            Logger.logInfo(UiFramework.loggerCategory(this), `UiItemsProvider ${uiProvider.id} registered as ${providerId} `);
            UiItemsManager.sendRegisteredEvent({ providerId });
        }
    }
    /** Remove a specific UiItemsProvider from the list of available providers. */
    static unregister(providerId) {
        if (this._abstractAdapter)
            return this._abstractAdapter.unregister(providerId);
        const provider = UiItemsManager.getUiItemsProvider(providerId);
        if (!provider)
            return;
        provider.onUnregister && provider.onUnregister();
        UiItemsManager._registeredUiItemsProviders.delete(providerId);
        Logger.logInfo(UiFramework.loggerCategory(this), `UiItemsProvider (${providerId}) unloaded`);
        // trigger a refresh of the ui
        UiItemsManager.sendRegisteredEvent({ providerId });
    }
    static allowItemsFromProvider(entry, stageId, stageUsage) {
        // istanbul ignore else
        const overrides = entry.overrides;
        if (undefined !== stageId &&
            (overrides === null || overrides === void 0 ? void 0 : overrides.stageIds) &&
            !overrides.stageIds.some((value) => value === stageId))
            return false;
        if (undefined !== stageUsage &&
            (overrides === null || overrides === void 0 ? void 0 : overrides.stageUsages) &&
            !overrides.stageUsages.some((value) => value === stageUsage))
            return false;
        return true;
    }
    /** Called when the application is populating a toolbar so that any registered UiItemsProvider can add tool buttons that either either execute
     * an action or specify a registered ToolId into toolbar.
     * @param stageId a string identifier of the active stage.
     * @param stageUsage the StageUsage of the active stage.
     * @param usage usage of the toolbar
     * @param orientation orientation of the toolbar
     * @returns an array of error messages. The array will be empty if the load is successful, otherwise it is a list of one or more problems.
     */
    static getToolbarButtonItems(stageId, stageUsage, usage, orientation) {
        if (this._abstractAdapter) {
            return this._abstractAdapter.getToolbarButtonItems(stageId, stageUsage, usage, orientation);
        }
        const items = [];
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            var _a, _b;
            if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                return;
            const uiProvider = entry.provider;
            const providerId = (_b = (_a = entry.overrides) === null || _a === void 0 ? void 0 : _a.providerId) !== null && _b !== void 0 ? _b : uiProvider.id;
            const provider = createGetPropertyAdapter(uiProvider);
            const providerItems = provider
                .provideToolbarItems(stageId, stageUsage, usage, orientation)
                .map((item) => ({
                ...item,
                providerId,
            }));
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
    /** Called when the application is populating the statusbar so that any registered UiItemsProvider can add status fields
     * @param stageId a string identifier of the active stage.
     * @param stageUsage the StageUsage of the active stage.
     * @returns An array of CommonStatusBarItem that will be used to create controls for the status bar.
     */
    static getStatusBarItems(stageId, stageUsage) {
        if (this._abstractAdapter) {
            return this._abstractAdapter.getStatusBarItems(stageId, stageUsage);
        }
        const items = [];
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            var _a, _b;
            if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                return;
            const uiProvider = entry.provider;
            const providerId = (_b = (_a = entry.overrides) === null || _a === void 0 ? void 0 : _a.providerId) !== null && _b !== void 0 ? _b : uiProvider.id;
            const provider = createGetPropertyAdapter(uiProvider);
            const providerItems = provider
                .provideStatusBarItems(stageId, stageUsage)
                .map((item) => ({
                ...item,
                providerId,
            }));
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
    /** Called when the application is populating the statusbar so that any registered UiItemsProvider can add status fields
     * @returns An array of BackstageItem that will be used to create controls for the backstage menu.
     */
    static getBackstageItems() {
        if (this._abstractAdapter) {
            return this._abstractAdapter.getBackstageItems();
        }
        const items = [];
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            var _a, _b;
            const uiProvider = entry.provider;
            const providerId = (_b = (_a = entry.overrides) === null || _a === void 0 ? void 0 : _a.providerId) !== null && _b !== void 0 ? _b : uiProvider.id;
            const provider = createGetPropertyAdapter(uiProvider);
            // Note: We do not call this.allowItemsFromProvider here as backstage items
            // should not be considered stage specific.
            const providerItems = provider.provideBackstageItems().map((item) => ({
                ...item,
                providerId,
            }));
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
    /** Called when the application is populating the Stage Panels so that any registered UiItemsProvider can add widgets
     * @param stageId a string identifier of the active stage.
     * @param stageUsage the StageUsage of the active stage.
     * @param location the location within the stage.
     * @param section the section within location.
     * @returns An array of widgets.
     */
    static getWidgets(stageId, stageUsage, location, section) {
        const items = [];
        if (this._abstractAdapter) {
            const abstractWidgets = this._abstractAdapter.getWidgets(stageId, stageUsage, location, section);
            items.push(...abstractWidgets);
        }
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            var _a, _b;
            const uiProvider = entry.provider;
            const providerId = (_b = (_a = entry.overrides) === null || _a === void 0 ? void 0 : _a.providerId) !== null && _b !== void 0 ? _b : uiProvider.id;
            if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                return;
            const provider = createGetPropertyAdapter(uiProvider);
            const providerItems = provider
                .provideWidgets(stageId, stageUsage, location, section)
                .map((item) => ({
                ...item,
                providerId,
            }));
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
}
UiItemsManager._registeredUiItemsProviders = new Map();
UiItemsManager._onUiProviderRegisteredEvent = new BeUiEvent();
UiItemsManager._abstractAdapter = createAbstractUiItemsManagerAdapter();
export { UiItemsManager };
function getUniqueItems(items) {
    const uniqueItems = [];
    items.forEach((item) => {
        if (uniqueItems.find((existingItem) => item.id === existingItem.id))
            return;
        uniqueItems.push(item);
    });
    return uniqueItems;
}
//# sourceMappingURL=UiItemsManager.js.map