import '../../globals.js';
// Copyright 2021-2025, University of Colorado Boulder
/**
 * This implementation auto-detects the enumeration values by Object.keys and instanceof. Every property that has a
 * type matching the enumeration type is marked as a value.  See sample usage in Orientation.ts.
 *
 * For general pattern see https://github.com/phetsims/phet-info/blob/main/doc/phet-software-design-patterns.md#enumeration
 *
 * This creates 2-way maps (key-to-value and value-to-key) for ease of use and to enable phet-io serialization.
 *
 * class T extends EnumerationValue {
 *     static a=new T();
 *     static b =new T();
 *     getName(){return 'he';}
 *     get thing(){return 'text';}
 *     static get age(){return 77;}
 *     static enumeration = new Enumeration( T );
 * }
 * T.enumeration.keys => ['a', 'b']
 * T.enumeration.values => [T, T]
 *
 * Note how `keys` only picks up 'a' and 'b'.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */
import affirm from '../../perennial-alias/js/browser-and-node/affirm.js';
import _ from 'lodash';
import EnumerationValue from './EnumerationValue.js';
import inheritance from './inheritance.js';
import optionize from './optionize.js';
import phetCore from './phetCore.js';
class Enumeration {
    constructor(Enumeration, providedOptions) {
        const options = optionize()({
            phetioDocumentation: '',
            // Values are plucked from the supplied Enumeration, but in order to support subtyping (augmenting) Enumerations,
            // you can specify the rule for what counts as a member of the enumeration. This should only be used in the
            // special case of augmenting existing enumerations.
            instanceType: Enumeration
        }, providedOptions);
        this.phetioDocumentation = options.phetioDocumentation;
        const instanceType = options.instanceType;
        // Iterate over the type hierarchy to support augmenting enumerations, but reverse so that newly added enumeration
        // values appear after previously existing enumeration values
        const types = _.reverse(inheritance(Enumeration));
        affirm(types.includes(instanceType), 'the specified type should be in its own hierarchy');
        this.keys = [];
        this.values = [];
        types.forEach(type => {
            Object.keys(type).forEach(key => {
                const value = type[key];
                if (value instanceof instanceType) {
                    affirm(key === key.toUpperCase(), 'keys should be upper case by convention');
                    this.keys.push(key);
                    this.values.push(value);
                    // Only assign this to the lowest Enumeration in the hierarchy. Otherwise this would overwrite the
                    // supertype-assigned Enumeration. See https://github.com/phetsims/phet-core/issues/102
                    if (value instanceof Enumeration) {
                        value.name = key;
                        value.enumeration = this;
                    }
                }
            });
        });
        affirm(this.keys.length > 0, 'no keys found');
        affirm(this.values.length > 0, 'no values found');
        this.Enumeration = Enumeration;
        EnumerationValue.sealedCache.add(Enumeration);
    }
    getKey(value) {
        return value.name;
    }
    getValue(key) {
        return this.Enumeration[key];
    }
    includes(value) {
        return this.values.includes(value);
    }
}
phetCore.register('Enumeration', Enumeration);
export default Enumeration;
//# sourceMappingURL=Enumeration.js.map