"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module State
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.StateManager = void 0;
// cSpell:ignore DEVTOOLS
const redux_1 = require("redux");
const core_bentley_1 = require("@itwin/core-bentley");
const appui_abstract_1 = require("@itwin/appui-abstract");
const FrameworkState_1 = require("./FrameworkState");
const ReducerRegistry_1 = require("./ReducerRegistry");
/**
 * Centralized state management class using  Redux actions, reducers and store. This class monitors the ReducerRegistry and will
 * automatically update the store when a new reducer is registered.  This allows the store to be incrementally constructed as modules
 * and/or extensions are loaded.
 * @public
 */
class StateManager {
    /**
     * StateManager construct.
     * @param defaultReducers Default set of Reducers used by the current application. If this object does not contain the [[FrameworkReducer]] it will automatically be added.
     */
    constructor(defaultReducers) {
        if (defaultReducers) {
            this._defaultReducers = defaultReducers;
            const keys = (Object.keys(defaultReducers));
            // ensure frameworkState is included in the set of defaultReducers
            if (-1 === keys.findIndex((key) => key === "frameworkState"))
                this._defaultReducers = { ...defaultReducers, frameworkState: FrameworkState_1.FrameworkReducer };
        }
        else {
            this._defaultReducers = { frameworkState: FrameworkState_1.FrameworkReducer };
        }
        const dynamicallyRegisteredReducers = ReducerRegistry_1.ReducerRegistryInstance.getReducers();
        let allReducers = this.combineDynamicAndDefaultReducers(dynamicallyRegisteredReducers, this._defaultReducers);
        // create the Redux Store.
        // istanbul ignore next
        // eslint-disable-next-line deprecation/deprecation
        this._store = (0, redux_1.createStore)(allReducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
        ReducerRegistry_1.ReducerRegistryInstance.setChangeListener((newDynamicReducers) => {
            allReducers = this.combineDynamicAndDefaultReducers(newDynamicReducers, this._defaultReducers);
            this._store.replaceReducer(allReducers);
        });
        StateManager._singletonStore = this._store;
    }
    /** Method to test if the StateManager has been initialized.
     * @param suppressErrorLog If true and the StateManager is not initialized a log message will be output.
     */
    static isInitialized(suppressErrorLog = false) {
        if (!StateManager._singletonStore) {
            if (!suppressErrorLog)
                core_bentley_1.Logger.logError(StateManager._LOG_CATEGORY, "Accessing store before it is created.");
            return false;
        }
        else {
            return true;
        }
    }
    /** Return the current Redux store. Useful when using connect method to connect a Ui Component to the store. */
    static get store() {
        if (StateManager.isInitialized()) {
            return StateManager._singletonStore;
        }
        else {
            throw new appui_abstract_1.UiError(StateManager._LOG_CATEGORY, `Redux Store has not been initialized`);
        }
    }
    /** Return the current state from the Redux store. */
    static get state() {
        if (StateManager.isInitialized()) {
            return StateManager._singletonStore.getState();
        }
        else {
            return undefined;
        }
    }
    combineDynamicAndDefaultReducers(dynamicallyRegisteredReducers, defaultReducers) {
        const allReducers = {
            ...defaultReducers,
            ...dynamicallyRegisteredReducers,
        };
        return (0, redux_1.combineReducers)(allReducers);
    }
    /** To be used only in unit test
     * @internal
     */
    static clearStore() {
        StateManager._singletonStore = undefined;
    }
}
exports.StateManager = StateManager;
StateManager._LOG_CATEGORY = "StateManager";
//# sourceMappingURL=StateManager.js.map