/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module SyncUi
 */
import { UiEventDispatcher } from "@itwin/appui-abstract";
import { Logger } from "@itwin/core-bentley";
import { IModelApp } from "@itwin/core-frontend";
import { getInstancesCount } from "@itwin/presentation-common";
import { Presentation } from "@itwin/presentation-frontend";
// cSpell:ignore configurableui
import { Backstage } from "../backstage/Backstage";
import { SessionStateActionId } from "../redux/SessionState";
import { UiFramework } from "../UiFramework";
import { WorkflowManager } from "../workflow/Workflow";
// cSpell:ignore activecontentchanged, activitymessageupdated, activitymessagecancelled, backstagecloseevent, backstageevent, contentlayoutactivated, contentcontrolactivated,
// cSpell:ignore elementtooltipchanged, frontstageactivated, inputfieldmessageadded, inputfieldmessageremoved, modalfrontstagechanged, modaldialogchanged
// cSpell:ignore navigationaidactivated, notificationmessageadded, toolactivated, taskactivated, widgetstatechanged, workflowactivated frontstageactivating
// cSpell:ignore frontstageready activeviewportchanged selectionsetchanged presentationselectionchanged viewstatechanged
// cSpell:ignore accudrawcompassmodechanged accudrawfieldlockchanged accudrawrotationchanged uisettingschanged
/** Event Id used to sync UI components. Used to refresh visibility or enable state of control.
 * @public
 */
export var SyncUiEventId;
(function (SyncUiEventId) {
    /** AccuDraw compass mode has changed. */
    SyncUiEventId["AccuDrawCompassModeChanged"] = "accudrawcompassmodechanged";
    /** AccuDraw rotation has changed. */
    SyncUiEventId["AccuDrawRotationChanged"] = "accudrawrotationchanged";
    /** The active content as maintained by the ContentViewManager has changed. */
    SyncUiEventId["ActiveContentChanged"] = "activecontentchanged";
    /** The active view maintained by the ViewManager has changed. */
    SyncUiEventId["ActiveViewportChanged"] = "activeviewportchanged";
    /** Backstage has been closed.
     * @deprecated in 3.7. Use BackstageEvent instead
     */
    SyncUiEventId["BackstageCloseEvent"] = "backstagecloseevent";
    /** Backstage has been closed. */
    SyncUiEventId["BackstageEvent"] = "backstageevent";
    /** A Content Layout has been activated.  */
    SyncUiEventId["ContentLayoutActivated"] = "contentlayoutactivated";
    /** A Content Control maintained by FrontstageManager has been activated. */
    SyncUiEventId["ContentControlActivated"] = "contentcontrolactivated";
    /** A Frontstage is activating. */
    SyncUiEventId["FrontstageActivating"] = "frontstageactivating";
    /** A Frontstage has been activated and the content has been assigned. */
    SyncUiEventId["FrontstageReady"] = "frontstageready";
    /** A Modal Frontstage has been opened or closed. */
    SyncUiEventId["ModalFrontstageChanged"] = "modalfrontstagechanged";
    /** A Modal Dialog has been opened or closed. */
    SyncUiEventId["ModalDialogChanged"] = "modaldialogchanged";
    /** A NavigationAid has been activated. */
    SyncUiEventId["NavigationAidActivated"] = "navigationaidactivated";
    /** An InteractiveTool has been activated via the ToolAdmin. */
    SyncUiEventId["ToolActivated"] = "toolactivated";
    /** A Task has been activated.
     * @deprecated in 3.0. Task is obsolete. */
    SyncUiEventId["TaskActivated"] = "taskactivated";
    /** The state of a Widget has changed. */
    SyncUiEventId["WidgetStateChanged"] = "widgetstatechanged";
    /** A Workflow has been activated.
     * @deprecated in 3.0. Workflow is obsolete. */
    SyncUiEventId["WorkflowActivated"] = "workflowactivated";
    /** The SelectionSet for the active IModelConnection has changed. */
    SyncUiEventId["SelectionSetChanged"] = "selectionsetchanged";
    /** The list of settings providers registered with SettingsManager has changed. */
    SyncUiEventId["SettingsProvidersChanged"] = "settingsproviderschanged";
    /** The current view state has changed (used by view undo/redo toolbar buttons). */
    SyncUiEventId["ViewStateChanged"] = "viewstatechanged";
    /** The current object the reads and write UI State has changed. */
    SyncUiEventId["UiStateStorageChanged"] = "uistatestoragechanged";
    SyncUiEventId["ShowHideManagerSettingChange"] = "show-hide-setting-change";
    /** The list of feature overrides applied has been changed
     * @alpha
    */
    SyncUiEventId["FeatureOverridesChanged"] = "featureoverrideschanged";
})(SyncUiEventId || (SyncUiEventId = {}));
/** This class is used to send eventIds to interested UI components so the component can determine if it needs
 * to refresh its display by calling setState on itself.
 * @public
 */
export class SyncUiEventDispatcher {
    /** @internal - used for testing only */
    /* istanbul ignore next */
    static setTimeoutPeriod(period) {
        SyncUiEventDispatcher._uiEventDispatcher.setTimeoutPeriod(period);
    }
    /** Return set of event ids that will be sent to listeners/. */
    static get syncEventIds() {
        return SyncUiEventDispatcher._uiEventDispatcher.syncEventIds;
    }
    /** Return SyncUiEvent so callers can register an event callback. */
    // eslint-disable-next-line deprecation/deprecation
    static get onSyncUiEvent() {
        return SyncUiEventDispatcher._uiEventDispatcher.onSyncUiEvent;
    }
    /** Immediately trigger sync event processing. */
    static dispatchImmediateSyncUiEvent(eventId) {
        SyncUiEventDispatcher._uiEventDispatcher.dispatchImmediateSyncUiEvent(eventId);
    }
    /** Save eventId in Set for processing. */
    static dispatchSyncUiEvent(eventId) {
        if (0 === SyncUiEventDispatcher._uiEventDispatcher.timeoutPeriod) {
            Logger.logInfo(UiFramework.loggerCategory(this), `[dispatchSyncUiEvent] not processed because timeoutPeriod=0`);
            return;
        }
        SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(eventId);
    }
    /** Save multiple eventIds in Set for processing. */
    static dispatchSyncUiEvents(eventIds) {
        // istanbul ignore if
        if (0 === SyncUiEventDispatcher._uiEventDispatcher.timeoutPeriod) {
            Logger.logInfo(UiFramework.loggerCategory(this), `[dispatchSyncUiEvents] not processed because _timeoutPeriod=0`);
        }
        SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvents(eventIds);
    }
    /** Checks to see if an eventId of interest is contained in the set of eventIds */
    static hasEventOfInterest(eventIds, idsOfInterest) {
        return SyncUiEventDispatcher._uiEventDispatcher.hasEventOfInterest(eventIds, idsOfInterest);
    }
    // istanbul ignore next
    static _dispatchViewChange() {
        SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ViewStateChanged);
    }
    // istanbul ignore next
    static _dispatchFeatureOverridesChange() {
        SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.FeatureOverridesChanged);
    }
    /** Initializes the Monitoring of Events that trigger dispatching sync events */
    static initialize() {
        // clear any registered listeners - this should only be encountered in unit test scenarios
        this._unregisterListenerFuncs.forEach((unregisterListenerFunc) => unregisterListenerFunc());
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onContentControlActivatedEvent.addListener(() => {
            SyncUiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ContentControlActivated);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onContentLayoutActivatedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ContentLayoutActivated);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onFrontstageActivatedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.FrontstageActivating);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onFrontstageReadyEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.FrontstageReady);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onModalFrontstageChangedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ModalFrontstageChanged);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onNavigationAidActivatedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.NavigationAidActivated);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onToolActivatedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ToolActivated);
        }));
        this._unregisterListenerFuncs.push(UiFramework.frontstages.onWidgetStateChangedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.WidgetStateChanged);
        }));
        this._unregisterListenerFuncs.push(Backstage.onBackstageEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.BackstageEvent);
        }));
        this._unregisterListenerFuncs.push(WorkflowManager.onTaskActivatedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.TaskActivated); // eslint-disable-line deprecation/deprecation
        }));
        this._unregisterListenerFuncs.push(WorkflowManager.onWorkflowActivatedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.WorkflowActivated); // eslint-disable-line deprecation/deprecation
        }));
        this._unregisterListenerFuncs.push(UiFramework.content.onActiveContentChangedEvent.addListener(() => {
            SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ActiveContentChanged);
        }));
        // istanbul ignore else
        if (IModelApp && IModelApp.viewManager) {
            this._unregisterListenerFuncs.push(IModelApp.viewManager.onSelectedViewportChanged.addListener((args) => {
                SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.ActiveViewportChanged);
                // if this is the first view being opened up start the default tool so tool admin is happy.
                if (undefined === args.previous) {
                    IModelApp.toolAdmin.startDefaultTool(); // eslint-disable-line @typescript-eslint/no-floating-promises
                }
                else {
                    // istanbul ignore next
                    if (args.previous.onViewChanged && typeof args.previous.onViewChanged.removeListener === "function") // not set during unit test
                        args.previous.onViewChanged.removeListener(SyncUiEventDispatcher._dispatchViewChange);
                    // istanbul ignore next
                    if (args.previous.onFeatureOverridesChanged && typeof args.previous.onFeatureOverridesChanged.removeListener === "function") // not set during unit test
                        args.previous.onFeatureOverridesChanged.removeListener(SyncUiEventDispatcher._dispatchFeatureOverridesChange);
                }
                // istanbul ignore next
                if (args.current) {
                    if (args.current.onViewChanged && typeof args.current.onViewChanged.addListener === "function") // not set during unit test
                        args.current.onViewChanged.addListener(SyncUiEventDispatcher._dispatchViewChange);
                    // istanbul ignore next
                    if (args.current.onFeatureOverridesChanged && typeof args.current.onFeatureOverridesChanged.addListener === "function") // not set during unit test
                        args.current.onFeatureOverridesChanged.addListener(SyncUiEventDispatcher._dispatchFeatureOverridesChange);
                }
            }));
        }
    }
    static selectionChangedHandler(_ev) {
        SyncUiEventDispatcher._uiEventDispatcher.dispatchSyncUiEvent(SyncUiEventId.SelectionSetChanged);
    }
    /** This should be called by IModelApp when the active IModelConnection is closed. */
    static clearConnectionEvents(iModelConnection) {
        iModelConnection.selectionSet.onChanged.removeListener(SyncUiEventDispatcher.selectionChangedHandler);
        SyncUiEventDispatcher._unregisterListenerFunc && SyncUiEventDispatcher._unregisterListenerFunc();
    }
    /** This should be called by IModelApp when the active IModelConnection is established. */
    static initializeConnectionEvents(iModelConnection) {
        if (SyncUiEventDispatcher._unregisterListenerFunc)
            SyncUiEventDispatcher._unregisterListenerFunc();
        if (iModelConnection.isBlankConnection() || !iModelConnection.isOpen) {
            UiFramework.dispatchActionToStore(SessionStateActionId.SetNumItemsSelected, 0);
            return;
        }
        iModelConnection.selectionSet.onChanged.removeListener(SyncUiEventDispatcher.selectionChangedHandler);
        iModelConnection.selectionSet.onChanged.addListener(SyncUiEventDispatcher.selectionChangedHandler);
        (iModelConnection.iModelId) ? UiFramework.setActiveIModelId(iModelConnection.iModelId) : /* istanbul ignore next */ "";
        // listen for changes from presentation rules selection manager (this is done once an iModelConnection is available to ensure Presentation.selection is valid)
        SyncUiEventDispatcher._unregisterListenerFunc = Presentation.selection.selectionChange.addListener((args, provider) => {
            // istanbul ignore if
            if (args.level !== 0) {
                // don't need to handle sub-selections
                return;
            }
            const selection = provider.getSelection(args.imodel, args.level);
            const numSelected = getInstancesCount(selection);
            UiFramework.dispatchActionToStore(SessionStateActionId.SetNumItemsSelected, numSelected);
        });
        try {
            Presentation.selection.scopes.getSelectionScopes(iModelConnection).then((availableScopes) => {
                // istanbul ignore else
                if (availableScopes) {
                    const presentationScopes = [];
                    availableScopes.map((scope) => presentationScopes.push(scope));
                    UiFramework.dispatchActionToStore(SessionStateActionId.SetAvailableSelectionScopes, presentationScopes);
                }
            });
            const activeSelectionScope = Presentation.selection.scopes.activeScope;
            if (activeSelectionScope) {
                if (typeof (activeSelectionScope) === "object") {
                    UiFramework.dispatchActionToStore(SessionStateActionId.SetSelectionScope, activeSelectionScope.id);
                }
                else {
                    UiFramework.dispatchActionToStore(SessionStateActionId.SetSelectionScope, activeSelectionScope);
                }
            }
        }
        catch { }
    }
}
SyncUiEventDispatcher._uiEventDispatcher = new UiEventDispatcher();
SyncUiEventDispatcher._unregisterListenerFuncs = [];
SyncUiEventDispatcher.initialized = false;
//# sourceMappingURL=SyncUiEventDispatcher.js.map