// #region Imports
import { PureEventEmitter } from '@breadstone/mosaik-elements';
// #endregion
/**
 * The `Theme` class.
 *
 * @public
 */
export class Theme {
    // #region Fields
    static _themeElements = [];
    _themeChanged;
    _schemeChanged;
    _paletteChanged;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `Theme` class.
     *
     * @public
     */
    constructor() {
        this._themeChanged = new PureEventEmitter();
        this._schemeChanged = new PureEventEmitter();
        this._paletteChanged = new PureEventEmitter();
    }
    // #endregion
    // #region Properties
    /**
     * @public
     * @readonly
     * @eventProperty
     */
    get themeChanged() {
        return this._themeChanged;
    }
    /**
     * @public
     * @readonly
     * @eventProperty
     */
    get schemeChanged() {
        return this._schemeChanged;
    }
    /**
     * @public
     * @readonly
     * @eventProperty
     */
    get paletteChanged() {
        return this._paletteChanged;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @static
     */
    static register(element) {
        Theme._themeElements.push(element);
    }
    /**
     * @public
     * @static
     */
    static unregister(element) {
        const index = Theme._themeElements.indexOf(element);
        if (index > -1) {
            Theme._themeElements.splice(index, 1);
        }
    }
    /**
     * @public
     */
    getTheme() {
        const current = Theme._themeElements.at(0)?.theme;
        if (!current) {
            throw new Error('No theme set.');
        }
        return current;
    }
    /**
     * Gets the current theme name from the document element.
     *
     * @public
     * @returns The current theme name or `null` if not set.
     */
    getDocumentTheme() {
        return document.documentElement.getAttribute('theme');
    }
    /**
     * Gets the current theme mode from the document element.
     *
     * @public
     * @returns The current theme mode or `null` if not set.
     */
    getDocumentThemeMode() {
        return document.documentElement.getAttribute('theme-mode');
    }
    /**
     * Applies the specified theme.
     *
     * @public
     * @param theme The theme to apply.
     */
    applyTheme(theme) {
        Theme._themeElements.forEach((element) => {
            element.applyTheme(theme);
        });
        this._themeChanged.emit({ theme: theme });
    }
    /**
     * Applies the specified scheme.
     *
     * @public
     * @param scheme The scheme to apply.
     */
    applyScheme(scheme) {
        Theme._themeElements.forEach((element) => {
            element.applyScheme(scheme);
        });
        this._schemeChanged.emit({ scheme: scheme });
    }
    /**
     * Applies the specified palette.
     *
     * @public
     * @param palette The palette to apply.
     */
    applyPalette(palette) {
        Theme._themeElements.forEach((element) => {
            element.applyPalette(palette);
        });
        this._paletteChanged.emit({ palette: palette });
    }
    /**
     * Applies the specified font family.
     *
     * @public
     * @param fontFamily The font family to apply.
     */
    applyFontFamily(fontFamily) {
        Theme._themeElements.forEach((element) => {
            element.applyFontFamily(fontFamily);
        });
    }
    /**
     * Applies the specified typography.
     *
     * @public
     * @param typography The typography to apply.
     */
    applyTypography(typography) {
        Theme._themeElements.forEach((element) => {
            element.applyTypography(typography);
        });
    }
    /**
     * Applies the specified layout.
     *
     * @public
     * @param layout The layout to apply.
     */
    applyLayout(layout) {
        Theme._themeElements.forEach((element) => {
            element.applyLayout(layout);
        });
    }
    /**
     * Applies the specified elevation.
     *
     * @public
     * @param elevation The elevation to apply.
     */
    applyElevation(elevation) {
        Theme._themeElements.forEach((element) => {
            element.applyElevation(elevation);
        });
    }
    /**
     * Replaces the scheme with the specified key.
     * This is useful when you want to replace a specific scheme in the theme.
     *
     * @public
     * @param mode The theme mode to replace.
     * @param scheme The scheme color roles to replace.
     */
    replaceScheme(mode, scheme) {
        Theme._themeElements.forEach((element) => {
            if (!element.theme?.scheme) {
                return;
            }
            const currentScheme = element.theme.scheme;
            const currentMode = currentScheme[mode];
            const mergedMode = Object.assign({}, currentMode, scheme);
            const updatedScheme = Object.assign({}, currentScheme, { [mode]: mergedMode });
            element.applyScheme(updatedScheme);
        });
        this._schemeChanged.emit({
            mode,
            scheme
        });
    }
    /**
     * Replaces the palette with the specified key.
     * This is useful when you want to replace a specific palette in the theme.
     *
     * @public
     * @param mode The theme mode to replace.
     * @param semantic The semantic color roles to replace.
     */
    replacePalette(mode, semantic) {
        Theme._themeElements.forEach((element) => {
            if (!element.theme?.palette) {
                return;
            }
            const currentPalette = element.theme.palette;
            const currentMode = currentPalette[mode];
            const mergedMode = Object.assign({}, currentMode, semantic);
            const updatedPalette = Object.assign({}, currentPalette, { [mode]: mergedMode });
            element.applyPalette(updatedPalette);
        });
        this._paletteChanged.emit({
            mode,
            semantic
        });
    }
}
/**
 * @public
 */
export class ThemeServiceLocator {
    // #region Fields
    static _current = null;
    // #endregion
    // #region Properties
    static get current() {
        if (!ThemeServiceLocator.isSet()) {
            throw new Error('\'Theme\' not set.');
        }
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        return ThemeServiceLocator._current;
    }
    // #endregion
    // #region Methods
    static isSet() {
        return ThemeServiceLocator._current !== null;
    }
    static set(current) {
        ThemeServiceLocator._current = current;
    }
}
ThemeServiceLocator.set(new Theme());
//# sourceMappingURL=Theme.js.map