import _ from 'lodash';
import '../../assert/js/assert.js';
import '../../globals.js';
// Copyright 2013-2024, University of Colorado Boulder
/**
 * AquaRadioButtonGroup creates a group of AquaRadioButtons and manages their layout.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */
import Emitter from '../../axon/js/Emitter.js';
import optionize, { combineOptions } from '../../phet-core/js/optionize.js';
import { assertNoAdditionalChildren, FlowBox, KeyboardUtils, ParallelDOM, PDOMPeer, SceneryConstants } from '../../scenery/js/imports.js';
import multiSelectionSoundPlayerFactory from '../../tambo/js/multiSelectionSoundPlayerFactory.js';
import Tandem from '../../tandem/js/Tandem.js';
import AquaRadioButton from './AquaRadioButton.js';
import { getGroupItemNodes } from './GroupItemOptions.js';
import sun from './sun.js';
import SunUtil from './SunUtil.js';
// pdom - An id for each instance of AquaRadioButtonGroup, passed to individual buttons in the group.
// Each button in a radio button group must have the same "name" attribute to be considered in a group, otherwise
// arrow keys will navigate all radio type inputs in the document.
let instanceCount = 0;
// to prefix instanceCount in case there are different kinds of "groups"
const CLASS_NAME = 'AquaRadioButtonGroup';
export default class AquaRadioButtonGroup extends FlowBox {
    constructor(property, items, providedOptions) {
        instanceCount++;
        const options = optionize()({
            // AquaRadioButtonGroupOptions
            touchAreaXDilation: 0,
            touchAreaYDilation: 0,
            mouseAreaXDilation: 0,
            mouseAreaYDilation: 0,
            // FlowBoxOptions
            orientation: 'vertical', // Aqua radio buttons are typically vertical, rarely horizontal
            spacing: 3, // space between each button, perpendicular to options.orientation
            stretch: true,
            disabledOpacity: SceneryConstants.DISABLED_OPACITY,
            // phet-io
            tandem: Tandem.REQUIRED,
            tandemNameSuffix: 'RadioButtonGroup',
            visiblePropertyOptions: { phetioFeatured: true },
            phetioEnabledPropertyInstrumented: true, // opt into default PhET-iO instrumented enabledProperty
            phetioFeatured: true,
            // pdom
            tagName: 'ul',
            labelTagName: 'h3',
            ariaRole: 'radiogroup',
            helpTextBehavior: ParallelDOM.HELP_TEXT_BEFORE_CONTENT,
            groupFocusHighlight: true
        }, providedOptions);
        const nodes = getGroupItemNodes(items, options.tandem);
        // Default to a left alignment for vertical layout
        if (options.orientation === 'vertical') {
            options.align = options.align || 'left';
        }
        // Create a radio button for each item
        const radioButtons = items.map((item, index) => {
            // @ts-expect-error - runtime check to prevent prior pattern, see https://github.com/phetsims/sun/issues/794
            assert && assert(!item.tandem, 'Cannot specify tandem any more');
            const node = nodes[index];
            assert && assert(!node.hasPDOMContent, 'Accessibility is provided by AquaRadioButton and accessibleName of the AquaRadioButtonGroupItem options. ' +
                'Additional PDOM content in the provided Node could break accessibility.');
            return new AquaRadioButton(property, item.value, node, combineOptions({
                a11yNameAttribute: CLASS_NAME + instanceCount,
                soundPlayer: multiSelectionSoundPlayerFactory.getSelectionSoundPlayer(index),
                tandem: item.tandemName ? options.tandem.createTandem(item.tandemName) :
                    options.tandem === Tandem.OPT_OUT ? Tandem.OPT_OUT :
                        Tandem.REQUIRED,
                // NOTE: This does NOT support dynamic orientation changes. If you need that, change RectangularButton to support
                // dynamic options
                touchAreaXDilation: options.orientation === 'horizontal' ? options.spacing / 2 : options.touchAreaXDilation,
                touchAreaYDilation: options.orientation === 'vertical' ? options.spacing / 2 : options.touchAreaYDilation,
                mouseAreaXDilation: options.orientation === 'horizontal' ? options.spacing / 2 : options.mouseAreaXDilation,
                mouseAreaYDilation: options.orientation === 'vertical' ? options.spacing / 2 : options.mouseAreaYDilation
            }, options.radioButtonOptions, item.options));
        });
        options.children = radioButtons;
        super(options);
        this.onInputEmitter = new Emitter();
        // pdom - this node's primary sibling is aria-labelledby its own label so the label content is read whenever
        // a member of the group receives focus
        this.addAriaLabelledbyAssociation({
            thisElementName: PDOMPeer.PRIMARY_SIBLING,
            otherNode: this,
            otherElementName: PDOMPeer.LABEL_SIBLING
        });
        // zoom - signify that key input is reserved and we should not pan when user presses arrow keys
        // See https://github.com/phetsims/scenery/issues/974
        const intentListener = {
            keydown: (event) => {
                if (KeyboardUtils.isArrowKey(event.domEvent)) {
                    event.pointer.reserveForKeyboardDrag();
                }
            }
        };
        this.addInputListener(intentListener);
        const boundOnRadioButtonInput = this.onRadioButtonInput.bind(this);
        for (let i = 0; i < radioButtons.length; i++) {
            const radioButton = radioButtons[i];
            radioButton.onInputEmitter.addListener(boundOnRadioButtonInput);
        }
        // Add linked element after the radio button is instrumented
        this.addLinkedElement(property, {
            tandemName: 'property'
        });
        assert && SunUtil.validateLinkedElementInstrumentation(this, property);
        this.disposeAquaRadioButtonGroup = () => {
            this.removeInputListener(intentListener);
            radioButtons.forEach(radioButton => radioButton.dispose());
            this.onInputEmitter.dispose();
            nodes.forEach(node => node.dispose());
        };
        this.radioButtons = radioButtons;
        // Decorating with additional content is an anti-pattern, see https://github.com/phetsims/sun/issues/860
        assert && assertNoAdditionalChildren(this);
    }
    onRadioButtonInput() {
        this.onInputEmitter.emit();
    }
    dispose() {
        this.disposeAquaRadioButtonGroup();
        super.dispose();
    }
    /**
     * Gets the radio button that corresponds to the specified value.
     */
    getButton(value) {
        const button = _.find(this.radioButtons, (radioButton) => radioButton.value === value);
        assert && assert(button, `no radio button found for value ${value}`);
        return button;
    }
}
sun.register('AquaRadioButtonGroup', AquaRadioButtonGroup);
//# sourceMappingURL=AquaRadioButtonGroup.js.map