import _ from 'lodash';
import '../../assert/js/assert.js';
import '../../tandem/js/PhetioIDUtils.js';
import '../../globals.js';
// Copyright 2022-2024, University of Colorado Boulder
/**
 * Sets up a system of Properties to handle translation fallback and phet-io support for a single translated string.
 *
 * @author Jonathan Olson <jonathan.olson>
 */
import TinyProperty from '../../axon/js/TinyProperty.js';
import localeProperty from '../../joist/js/i18n/localeProperty.js';
import arrayRemove from '../../phet-core/js/arrayRemove.js';
import chipper from './chipper.js';
import { localizedStrings } from './getStringModule.js';
import LocalizedStringProperty from './LocalizedStringProperty.js';
// constants
const FALLBACK_LOCALE = 'en';
const localeData = phet.chipper.localeData;
assert && assert(localeData, 'localeData expected but global has not been set');
class LocalizedString {
    constructor(stringKey, 
    // Store initial values, so we can handle state deltas
    localeToTranslationMap, tandem, metadata) {
        this.stringKey = stringKey;
        this.localeToTranslationMap = localeToTranslationMap;
        // Uses lazy creation of locales
        this.localePropertyMap = new Map();
        // Store initial values, so we can handle state deltas
        this.initialValues = {};
        this.property = new LocalizedStringProperty(this, tandem, metadata);
        // Add to a global list to support PhET-iO serialization and internal testing
        localizedStrings.push(this);
    }
    /**
     * Returns an object that shows the changes of strings from their initial values. This includes whether strings are
     * marked as "overridden"
     */
    getStateDelta() {
        const result = {};
        this.usedLocales.forEach(locale => {
            const initialValue = this.initialValues[locale];
            const currentValue = this.getLocaleSpecificProperty(locale).value;
            if (currentValue !== initialValue) {
                result[locale] = currentValue;
            }
        });
        return result;
    }
    /**
     * Take a state from getStateDelta, and apply it.
     */
    setStateDelta(state) {
        // Create potential new locales (since locale-specific Properties are lazily created as needed
        Object.keys(state).forEach(locale => this.getLocaleSpecificProperty(locale));
        this.usedLocales.forEach(locale => {
            const localeSpecificProperty = this.getLocaleSpecificProperty(locale);
            const initialValue = this.initialValues[locale];
            assert && assert(initialValue !== undefined);
            const stateValue = state[locale] !== undefined ? state[locale] : null;
            localeSpecificProperty.value = stateValue ?? initialValue;
        });
    }
    get usedLocales() {
        return [...this.localePropertyMap.keys()];
    }
    /**
     * Returns the locale-specific Property for any locale (lazily creating it if necessary)
     */
    getLocaleSpecificProperty(locale) {
        // Lazy creation
        if (!this.localePropertyMap.has(locale)) {
            // Locales in order of fallback
            const orderedLocales = LocalizedString.getLocaleFallbacks(locale);
            // Find the first-defined value
            let initialValue = null;
            for (const locale of orderedLocales) {
                if (this.localeToTranslationMap[locale] !== undefined) {
                    initialValue = this.localeToTranslationMap[locale];
                    break;
                }
            }
            // Should be guaranteed because of `en` as a fallback
            assert && assert(initialValue !== undefined, 'no initial value found for', locale);
            this.initialValues[locale] = initialValue;
            this.localePropertyMap.set(locale, new TinyProperty(initialValue));
        }
        return this.localePropertyMap.get(locale);
    }
    dispose() {
        this.property.dispose();
        arrayRemove(localizedStrings, this);
    }
    /**
     * Reset to the initial value for the specified locale, used for testing.
     */
    restoreInitialValue(locale) {
        assert && assert(typeof this.initialValues[locale] === 'string', 'initial value expected for', locale);
        this.property.value = this.initialValues[locale];
    }
    static getLocaleFallbacks(locale = localeProperty.value) {
        return _.uniq([
            locale,
            ...(localeData[locale].fallbackLocales || []),
            FALLBACK_LOCALE
        ]);
    }
}
chipper.register('LocalizedString', LocalizedString);
export default LocalizedString;
//# sourceMappingURL=LocalizedString.js.map