// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var ChoiceGroupElement_1;
import { HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Emit } from '../../../../events/Decorators/EmitDecorator';
import { EID } from '../../../../Utilities/EId';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Disableable } from '../../../Behaviors/Disableable';
import { Invalidable } from '../../../Behaviors/Invalidable';
import { Orientable } from '../../../Behaviors/Orientable';
import { Slottable } from '../../../Behaviors/Slottable';
import { Themeable } from '../../../Behaviors/Themeable';
import { Valueable } from '../../../Behaviors/Valueable';
import { Variantable } from '../../../Behaviors/Variantable';
import { addInheritanceProviderController } from '../../../Controllers/InheritanceProviderController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ChoiceElement } from './ChoiceElement';
import { choiceGroupElementTemplate } from './ChoiceGroupElementTemplate';
import { ChoiceGroupHeaderElement } from './ChoiceGroupHeaderElement';
import { CHOICE_GROUP_INHERITANCE_CONTEXT } from './ChoiceGroupInheritanceContext';
import { choiceGroupElementCosmopolitanStyle } from './Themes/ChoiceGroupElement.Cosmopolitan';
import { choiceGroupElementJoyStyle } from './Themes/ChoiceGroupElement.Joy';
import { choiceGroupElementMemphisStyle } from './Themes/ChoiceGroupElement.Memphis';
// #endregion
/**
 * Choice Group - A container for grouping multiple choices, such as radio buttons or checkboxes.
 *
 * @element mosaik-choice-group
 *
 * @description
 * The Choice Group component is used to organize and manage a set of choices, allowing users to select one or more options from the group. It typically contains multiple Choice components, each representing an individual option. Common examples of Choice Groups include radio button groups and checkbox groups.
 *
 * @category Forms
 *
 * @fires choiceChanged {GroupChangedEvent} - Called when the value of the `ChoiceGroupElement` changes.
 *
 * @example
 * ```html
 * <mosaik-choice-group>
 *   <mosaik-choice>Option 1</mosaik-choice>
 *   <mosaik-choice>Option 2</mosaik-choice>
 *   <mosaik-choice>Option 3</mosaik-choice>
 * </mosaik-choice-group>
 * ```
 *
 * @public
 */
let ChoiceGroupElement = ChoiceGroupElement_1 = class ChoiceGroupElement extends Themeable(Orientable(Invalidable(Valueable(Disableable(Appearanceable(Variantable(Slottable(CustomElement)))))))) {
    // #region Fields
    _provider = addInheritanceProviderController(this, {
        context: CHOICE_GROUP_INHERITANCE_CONTEXT,
        values: () => ({
            disabled: this.disabled,
            appearance: this.appearance,
            variant: this.variant,
            name: this.name,
            dir: this.dir
        })
    });
    _choiceChanged;
    _name;
    _required;
    _eventSubscriptions;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._name = EID.next(ChoiceGroupElement_1.is);
        this._required = false;
        this._choiceChanged = new HTMLElementEventEmitter(this, 'choiceChanged');
        this._eventSubscriptions = new Array();
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `{@link is}` property.
     * The `{@link is}` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-choice-group';
    }
    /**
     * Gets or sets the `name` property.
     *
     * @public
     * @attr
     */
    get name() {
        return this._name;
    }
    set name(value) {
        if (this._name !== value) {
            this._name = value;
            this.requestUpdate('name');
        }
    }
    /**
     * Gets or sets the `required` property.
     *
     * @public
     * @attr
     */
    get required() {
        return this._required;
    }
    set required(value) {
        if (this._required !== value) {
            this._required = value;
            this.requestUpdate('required');
        }
    }
    // #endregion
    // #region Events
    /**
     * Called when the value of the `ChoiceGroupElement` changes.
     * Provides reference to `{@link IEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get choiceChanged() {
        return this._choiceChanged;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    onSlotChanges() {
        this.clearEvents();
        const elements = this.getSlotAssignments('')
            .filter((x) => x instanceof ChoiceElement);
        for (const [i, e] of elements.entries()) {
            e.isChecked = this.value === e.value;
            e.classList.add('choice-group-choice');
            e.classList.toggle('first', i === 0);
            e.classList.toggle('inner', i > 0 && i < elements.length - 1);
            e.classList.toggle('last', i === elements.length - 1);
            this._eventSubscriptions.push(e.on('checked', (x) => this.onChoiceCheckChanged(x), { passive: true }));
        }
    }
    /**
     * Returns whether a form will validate when it is submitted, without having to submit it.
     *
     * @public
     * @override
     */
    checkValidity() {
        const elements = this.getSlotAssignments('')
            .filter((x) => x instanceof ChoiceElement)
            .filter((x) => x.isChecked ?? false);
        return elements.length > 0;
    }
    /**
     * Resets the element to its initial state.
     *
     * @public
     */
    reset() {
        const elements = this.getSlotAssignments('')
            .filter((x) => x instanceof ChoiceElement);
        elements.forEach((x) => x.uncheck());
        this.invalid = false;
    }
    /**
     * Emits the {@link choiceChanged} event.
     *
     * @protected
     */
    onChoiceChanged(args) {
        this._choiceChanged.emit(args);
    }
    /**
     * @protected
     */
    onValuePropertyChange(_prev, next) {
        const elements = this.getSlotAssignments('')
            .filter((x) => x instanceof ChoiceElement);
        elements.forEach((x) => x.isChecked = next?.includes(x.value) ?? false);
    }
    /**
     * @private
     */
    onChoiceCheckChanged(event) {
        const elements = this.getSlotAssignments('')
            .filter((x) => x instanceof ChoiceElement);
        // exclude the current element and uncheck all other elements
        elements.filter((x) => x !== event.target)
            .forEach((x) => x.uncheck());
        this.value = event.target.value;
        this.onChoiceChanged({ value: event.target.value });
    }
    /**
     * @private
     */
    clearEvents() {
        this._eventSubscriptions.forEach((x) => x.dispose());
        this._eventSubscriptions = [];
    }
};
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], ChoiceGroupElement.prototype, "name", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], ChoiceGroupElement.prototype, "required", null);
__decorate([
    Emit({ eventName: 'choiceChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], ChoiceGroupElement.prototype, "choiceChanged", null);
__decorate([
    Watch('value'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Array]),
    __metadata("design:returntype", void 0)
], ChoiceGroupElement.prototype, "onValuePropertyChange", null);
ChoiceGroupElement = ChoiceGroupElement_1 = __decorate([
    Component({
        selector: 'mosaik-choice-group',
        template: choiceGroupElementTemplate,
        themes: {
            joy: choiceGroupElementJoyStyle,
            memphis: choiceGroupElementMemphisStyle,
            cosmopolitan: choiceGroupElementCosmopolitanStyle
        },
        host: {
            role: 'group'
        },
        imports: [
            ChoiceElement,
            ChoiceGroupHeaderElement
        ]
    }),
    __metadata("design:paramtypes", [])
], ChoiceGroupElement);
export { ChoiceGroupElement };
//# sourceMappingURL=ChoiceGroupElement.js.map