import '../../../assert/js/assert.js';
import '../../../globals.js';
// Copyright 2024, University of Colorado Boulder
/**
 * A collection of fields that describes keys for a Hotkey. This includes a key that should be pressed to fire the
 * behavior, modifier keys that must be pressed in addition to the key, and ignored modifier keys that will not prevent
 * the hotkey from firing even if they are down.
 *
 * See the KeyDescriptorOptions for detailed information.
 *
 * @author Jesse Greenberg (PhET Interactive Simulations)
 */
import { metaEnglishKeys, scenery } from '../imports.js';
import optionize from '../../../phet-core/js/optionize.js';
const IGNORE_DELIMITER = '?';
export default class KeyDescriptor {
    constructor(providedOptions) {
        const options = optionize()({
            modifierKeys: [],
            ignoredModifierKeys: []
        }, providedOptions);
        this.key = options.key;
        this.modifierKeys = options.modifierKeys;
        this.ignoredModifierKeys = options.ignoredModifierKeys;
    }
    /**
     * Returns a string representation of the hotkey in the format of "natural" english. Modifier keys first, followed
     * by the final key. For example, if the key is 't' and the modifier keys are 'shift', the string would be 'shift+t'.
     */
    getHotkeyString() {
        return [
            ...this.modifierKeys,
            this.key
        ].join('+');
    }
    /**
     * Parses an input string to extract the main key and its associated modifier keys, while considering ignored
     * modifier keys based on the placement of the '?' delimiter.
     *
     * See KeyboardListener for a description of key and modifierKey behavior.
     *
     * The function handles the following cases:
     * 1. If a word is followed by '?', it is added to `ignoredModifierKeys`.
     * 2. If a word is preceded by '?', it indicates all other default modifier keys should be ignored,
     *    except the word itself, which is added to `modifierKeys`.
     *
     * keyStrokeToKeyDescriptor('r');
     * // Output: { key: 'r', modifierKeys: [], ignoredModifierKeys: [] }
     *
     * keyStrokeToKeyDescriptor('alt+r');
     * // Output: { key: 'r', modifierKeys: ['alt'], ignoredModifierKeys: [] }
     *
     * keyStrokeToKeyDescriptor('alt+j+r');
     * // Output: { key: 'r', modifierKeys: ['alt', 'j'], ignoredModifierKeys: [] }
     *
     * keyStrokeToKeyDescriptor('alt?+j+r');
     * // Output: { key: 'r', modifierKeys: ['j'], ignoredModifierKeys: ['alt'] }
     *
     * keyStrokeToKeyDescriptor('shift?+t');
     * // Output: { key: 't', modifierKeys: [], ignoredModifierKeys: ['shift'] }
     *
     * keyStrokeToKeyDescriptor('?shift+t');
     * // Output: { key: 't', modifierKeys: ['shift'], ignoredModifierKeys: ['alt', 'control', 'meta'] }
     *
     * keyStrokeToKeyDescriptor('?shift+t+j');
     * // Output: { key: 'j', modifierKeys: ['shift', 't'], ignoredModifierKeys: ['alt', 'control', 'meta'] }
     *
     */
    static keyStrokeToKeyDescriptor(keyStroke) {
        const tokens = keyStroke.split('+');
        // assertions
        let foundIgnoreDelimiter = false;
        tokens.forEach(token => {
            // the ignore delimiter can only be used on default modifier keys
            if (token.length > 1 && token.includes(IGNORE_DELIMITER)) {
                assert && assert(!foundIgnoreDelimiter, 'There can only be one ignore delimiter');
                assert && assert(metaEnglishKeys.includes(token.replace(IGNORE_DELIMITER, '')), 'The ignore delimiter can only be used on default modifier keys');
                foundIgnoreDelimiter = true;
            }
        });
        const modifierKeys = [];
        const ignoredModifierKeys = [];
        tokens.forEach(token => {
            // Check if the token contains a question mark
            if (token.includes(IGNORE_DELIMITER)) {
                const strippedToken = token.replace(IGNORE_DELIMITER, '');
                if (token.startsWith(IGNORE_DELIMITER)) {
                    // Add all default modifiers except the current stripped token to the ignored keys
                    const otherModifiers = metaEnglishKeys.filter(mod => mod !== strippedToken);
                    ignoredModifierKeys.push(...otherModifiers);
                    // Include the stripped token as a regular modifier key
                    modifierKeys.push(strippedToken);
                }
                else {
                    // Add the stripped token to the ignored modifier keys
                    ignoredModifierKeys.push(strippedToken);
                }
            }
            else {
                // If there's no question mark, add the token to the modifier keys
                modifierKeys.push(token);
            }
        });
        // Assume the last token is the key
        const key = modifierKeys.pop();
        // Filter out ignored modifier keys from the modifier keys list
        const filteredModifierKeys = modifierKeys.filter(mod => !ignoredModifierKeys.includes(mod));
        return new KeyDescriptor({
            key: key,
            modifierKeys: filteredModifierKeys,
            ignoredModifierKeys: ignoredModifierKeys
        });
    }
}
scenery.register('KeyDescriptor', KeyDescriptor);
//# sourceMappingURL=KeyDescriptor.js.map