/*---------------------------------------------------------------------------------------------
 * 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.js";
import { createAbstractUiItemsManagerAdapter, createGetPropertyAdapter, } from "./AbstractUiItemsManager.js";
/** Controls registering of UiItemsProviders and calls the provider's methods when populating different parts of the User Interface.
 * @public
 */
export 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) {
            this._abstractAdapter.clearAllProviders();
        }
        UiItemsManager._registeredUiItemsProviders.clear();
    }
    /** Event raised any time a UiProvider is registered or unregistered. */
    // eslint-disable-next-line @typescript-eslint/no-deprecated
    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) {
        if (this._abstractAdapter)
            return this._abstractAdapter.getUiItemsProvider(providerId);
        return UiItemsManager._registeredUiItemsProviders.get(providerId)?.provider;
    }
    // eslint-disable-next-line @typescript-eslint/no-deprecated
    static sendRegisteredEvent(args) {
        UiItemsManager.onUiProviderRegisteredEvent.raiseEvent(args);
    }
    /**
     * Registers an {@link UiItemsProvider}.
     * Optional overrides can be specified to limit when the provider is allowed to provide items.
     */
    static register(uiProvider, overrides) {
        const providerId = overrides?.providerId ?? uiProvider.id;
        if (UiItemsManager.getUiItemsProvider(providerId)) {
            Logger.logInfo(UiFramework.loggerCategory("UiItemsManager"), `UiItemsProvider '${providerId}' is already registered`);
            return;
        }
        // Using the same structure to support layout agnostic methods i.e. `getToolbarItems`.
        UiItemsManager._registeredUiItemsProviders.set(providerId, {
            provider: uiProvider,
            overrides,
        });
        if (this._abstractAdapter) {
            return this._abstractAdapter.register(uiProvider, overrides);
        }
        Logger.logInfo(UiFramework.loggerCategory("UiItemsManager"), `UiItemsProvider '${uiProvider.id}' registered as '${providerId}'`);
        UiItemsManager.sendRegisteredEvent({ providerId });
    }
    /** Unregisters a specific {@link UiItemsProvider}. */
    static unregister(providerId) {
        const provider = UiItemsManager.getUiItemsProvider(providerId);
        if (!provider)
            return;
        UiItemsManager._registeredUiItemsProviders.delete(providerId);
        if (this._abstractAdapter) {
            this._abstractAdapter.unregister(providerId);
        }
        provider.onUnregister?.();
        Logger.logInfo(UiFramework.loggerCategory("UiItemsManager"), `UiItemsProvider '${providerId}' unregistered`);
        // trigger a refresh of the ui
        UiItemsManager.sendRegisteredEvent({ providerId });
    }
    static allowItemsFromProvider(entry, stageId, stageUsage) {
        const overrides = entry.overrides;
        if (undefined !== stageId &&
            overrides?.stageIds &&
            !overrides.stageIds.some((value) => value === stageId))
            return false;
        if (undefined !== stageUsage &&
            overrides?.stageUsages &&
            !overrides.stageUsages.some((value) => value === stageUsage))
            return false;
        return true;
    }
    /** Returns registered toolbar items configured for the standard layout that match the specified frontstage id and usage.
     * @note Items registered in `UiItemsManager` of `@itwin/appui-abstract` are returned by this method.
     * @note Items returned by {@link UiItemsProvider.provideToolbarItems} are returned by this method.
     */
    static getToolbarButtonItems(stageId, stageUsage, usage, orientation) {
        if (this._abstractAdapter) {
            return this._abstractAdapter.getToolbarButtonItems(stageId, stageUsage, usage, orientation);
        }
        const items = [];
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                return;
            const uiProvider = entry.provider;
            const providerId = entry.overrides?.providerId ?? uiProvider.id;
            const provider = createGetPropertyAdapter(uiProvider);
            const providerItems = provider
                .provideToolbarItems(stageId, stageUsage, usage, orientation)
                .map((item) => ({
                ...item,
                providerId,
            }));
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
    /** Returns registered toolbar items that match the specified frontstage id and usage.
     * @note Items registered in `UiItemsManager` of `@itwin/appui-abstract` are not returned by this method.
     * @note Items returned by {@link UiItemsProvider.provideToolbarItems} are not returned by this method.
     */
    static getToolbarItems(stageId, stageUsage) {
        const items = [];
        // Not using `AbstractUiItemsManager`, since there's no way to check if provider items are allowed.
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            const uiProvider = entry.provider;
            const providerId = entry.overrides?.providerId ?? uiProvider.id;
            if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                return;
            const providerItems = uiProvider.getToolbarItems?.().map((item) => ({
                ...item,
                providerId,
            })) ?? [];
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
    /** Returns registered status bar items that match the specified frontstage id and usage.
     * @note Items registered in `UiItemsManager` of `@itwin/appui-abstract` are returned by this method.
     * @note Items returned by {@link UiItemsProvider.provideStatusBarItems} are returned by this method.
     */
    static getStatusBarItems(stageId, stageUsage) {
        if (this._abstractAdapter) {
            return this._abstractAdapter.getStatusBarItems(stageId, stageUsage);
        }
        const items = [];
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                return;
            const uiProvider = entry.provider;
            const providerId = entry.overrides?.providerId ?? uiProvider.id;
            const provider = createGetPropertyAdapter(uiProvider);
            const providerItems = provider
                .provideStatusBarItems(stageId, stageUsage)
                .map((item) => ({
                ...item,
                providerId,
            }));
            items.push(...providerItems);
        });
        return getUniqueItems(items);
    }
    /** Returns registered backstage items.
     * @note Items registered in `UiItemsManager` of `@itwin/appui-abstract` are returned by this method.
     * @note Items returned by {@link UiItemsProvider.provideBackstageItems} are returned by this method.
     */
    static getBackstageItems() {
        if (this._abstractAdapter) {
            return this._abstractAdapter.getBackstageItems();
        }
        const items = [];
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            const uiProvider = entry.provider;
            const providerId = entry.overrides?.providerId ?? 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);
    }
    static getWidgets(stageId, stageUsage, location, section) {
        const items = [];
        // If location is not specified, return all registered widgets.
        if (location === undefined) {
            // Not using `AbstractUiItemsManager`, since there's no way to check if provider items are allowed.
            UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
                const uiProvider = entry.provider;
                const providerId = entry.overrides?.providerId ?? uiProvider.id;
                if (!this.allowItemsFromProvider(entry, stageId, stageUsage))
                    return;
                const providerItems = uiProvider.getWidgets?.().map((item) => ({
                    ...item,
                    providerId,
                })) ?? [];
                items.push(...providerItems);
            });
            return getUniqueItems(items);
        }
        if (this._abstractAdapter) {
            const abstractWidgets = this._abstractAdapter.getWidgets(stageId, stageUsage, location, section);
            items.push(...abstractWidgets);
        }
        UiItemsManager._registeredUiItemsProviders.forEach((entry) => {
            const uiProvider = entry.provider;
            const providerId = entry.overrides?.providerId ?? 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(); // eslint-disable-line @typescript-eslint/no-deprecated
UiItemsManager._abstractAdapter = createAbstractUiItemsManagerAdapter();
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