import { ChangeDetectionStrategy, Component, ContentChildren, EventEmitter, forwardRef, Input, Output, QueryList, PLATFORM_ID, Inject, ElementRef, } from '@angular/core';
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { from, fromEvent, merge, Subject } from 'rxjs';
import { filter, startWith, switchMap, takeUntil } from 'rxjs/operators';
import { RRadioComponent } from './radio.component';
export class RRadioGroupComponent {
    constructor(hostElement, platformId, document) {
        this.hostElement = hostElement;
        this.platformId = platformId;
        this.document = document;
        this.destroy$ = new Subject();
        this.onChange = (value) => { };
        this.onTouched = () => { };
        this._status = 'basic';
        this.valueChange = new EventEmitter();
    }
    get value() {
        return this._value;
    }
    set value(value) {
        this._value = value;
        this.updateValues();
    }
    get name() {
        return this._name;
    }
    set name(name) {
        this._name = name;
        this.updateNames();
    }
    get disabled() {
        return this._disabled;
    }
    set disabled(disabled) {
        this._disabled = !!disabled;
        this.updateDisabled();
    }
    get status() {
        return this._status;
    }
    set status(value) {
        if (this._status !== value) {
            this._status = value;
            this.updateStatus();
        }
    }
    ngAfterContentInit() {
        // In case option 'name' isn't set on r-radio component,
        // we need to set it's name right away, so it won't overlap with options
        // without names from other radio groups. Otherwise they all would have
        // same name and will be considered as options from one group so only the
        // last option will stay selected.
        this.updateNames();
        this.radios.changes
            .pipe(startWith(this.radios), 
        // 'changes' emit during change detection run and we can't update
        // option properties right of since they already was initialized.
        // Instead we schedule microtask to update radios after change detection
        // run is finished and trigger one more change detection run.
        switchMap((radios) => from(Promise.resolve(radios))), takeUntil(this.destroy$))
            .subscribe(() => this.updateAndSubscribeToRadios());
    }
    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
    registerOnChange(fn) {
        this.onChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    writeValue(value) {
        this.value = value;
    }
    updateAndSubscribeToRadios() {
        this.updateValueFromCheckedOption();
        this.updateNames();
        this.updateValues();
        this.updateDisabled();
        this.updateStatus();
        this.subscribeOnRadiosValueChange();
        this.subscribeOnRadiosBlur();
    }
    updateNames() {
        if (this.radios) {
            this.radios.forEach((radio) => radio._setName(this.name));
        }
    }
    updateValues() {
        this.updateAndMarkForCheckRadios((radio) => radio.checked = radio.value === this.value);
    }
    updateDisabled() {
        if (typeof this.disabled !== 'undefined') {
            this.updateAndMarkForCheckRadios((radio) => radio.disabled = this.disabled);
        }
    }
    subscribeOnRadiosValueChange() {
        if (!this.radios || !this.radios.length) {
            return;
        }
        merge(...this.radios.map((radio) => radio.valueChange))
            .pipe(takeUntil(merge(this.radios.changes, this.destroy$)))
            .subscribe((value) => {
            this.writeValue(value);
            this.propagateValue(value);
        });
    }
    propagateValue(value) {
        this.valueChange.emit(value);
        this.onChange(value);
    }
    subscribeOnRadiosBlur() {
        const hasNoRadios = !this.radios || !this.radios.length;
        if (!isPlatformBrowser(this.platformId) || hasNoRadios) {
            return;
        }
        const hostElement = this.hostElement.nativeElement;
        fromEvent(hostElement, 'focusin')
            .pipe(filter(event => hostElement.contains(event.target)), switchMap(() => merge(fromEvent(this.document, 'focusin'), fromEvent(this.document, 'click'))), filter(event => !hostElement.contains(event.target)), takeUntil(merge(this.radios.changes, this.destroy$)))
            .subscribe(() => this.onTouched());
    }
    updateStatus() {
        this.updateAndMarkForCheckRadios((radio) => radio.status = this.status);
    }
    updateAndMarkForCheckRadios(updateFn) {
        if (this.radios) {
            this.radios.forEach((radio) => {
                updateFn(radio);
                radio._markForCheck();
            });
        }
    }
    updateValueFromCheckedOption() {
        const checkedRadio = this.radios.find((radio) => radio.checked);
        const isValueMissing = this.value === undefined || this.value === null;
        if (checkedRadio && isValueMissing && checkedRadio.value !== this.value) {
            this.value = checkedRadio.value;
        }
    }
}
RRadioGroupComponent.decorators = [
    { type: Component, args: [{
                selector: 'r-radio-group',
                template: `
    <ng-content select="r-radio"></ng-content>`,
                providers: [
                    {
                        provide: NG_VALUE_ACCESSOR,
                        useExisting: forwardRef(() => RRadioGroupComponent),
                        multi: true,
                    },
                ],
                changeDetection: ChangeDetectionStrategy.OnPush
            },] }
];
RRadioGroupComponent.ctorParameters = () => [
    { type: ElementRef },
    { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] },
    { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
];
RRadioGroupComponent.propDecorators = {
    value: [{ type: Input }],
    name: [{ type: Input }],
    disabled: [{ type: Input }],
    status: [{ type: Input }],
    radios: [{ type: ContentChildren, args: [RRadioComponent, { descendants: true },] }],
    valueChange: [{ type: Output }]
};
//# sourceMappingURL=radio-group.component.js.map