import * as i0 from '@angular/core';
import { forwardRef, Directive, Input, isDevMode, INJECTOR, Injector, Inject, runInInjectionContext, SkipSelf, Optional, HostBinding, HostListener, Renderer2, ElementRef, Self, TemplateRef, ViewContainerRef, ChangeDetectorRef, NgModule, inject, InjectionToken, Injectable, ComponentFactoryResolver } from '@angular/core';
import * as i1$1 from '@angular/forms';
import { NG_VALIDATORS, UntypedFormGroup, UntypedFormArray, ControlContainer, NgControl } from '@angular/forms';
import { __decorate, __metadata } from 'tslib';
import * as i1 from '@rxap/data-source';
import { PipeDataSource, DataSourceLoader, BaseDataSource, RXAP_DATA_SOURCE_METADATA } from '@rxap/data-source';
import { Mixin } from '@rxap/mixin';
import { RxapFormControl, RxapFormGroup, RxapFormArray, RXAP_FORM_CONTEXT } from '@rxap/forms';
import { map, tap, startWith as startWith$1, catchError, throttleTime, distinctUntilChanged as distinctUntilChanged$1, switchMap, shareReplay } from 'rxjs/operators';
import { setMetadataMapMap, getMetadata, setMetadataMap, setMetadata } from '@rxap/reflect-metadata';
import { RxapError, isPromiseLike, isPromise, equals } from '@rxap/utilities';
import { ToMethod } from '@rxap/pattern';
import { debounceTime, map as map$1, distinctUntilChanged, startWith, pairwise, tap as tap$1, Subscription, of, EMPTY } from 'rxjs';
import * as i2 from '@angular/material/button';
import * as i3 from '@angular/material/form-field';
import { MAT_FORM_FIELD, MatFormField } from '@angular/material/form-field';
import '@angular/material/autocomplete';
import * as i2$1 from '@rxap/remote-method';
import { RemoteMethodLoader, ProxyRemoteMethod } from '@rxap/remote-method';

class IsEqualToDirective {
    set equalTo(value) {
        this._equalTo = value;
        if (this._onChange) {
            this._onChange();
        }
    }
    validate(control) {
        if (this._equalTo === null || this._equalTo === control.value) {
            return null;
        }
        return {
            isEqualTo: {
                value: this._equalTo,
                actualValue: control.value,
            },
        };
    }
    /**
     * @description
     * Registers a callback function to call when the validator inputs change.
     *
     * @param fn The callback function
     */
    registerOnValidatorChange(fn) {
        this._onChange = fn;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: IsEqualToDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: IsEqualToDirective, isStandalone: true, selector: "[rxapIsEqualTo]", inputs: { equalTo: ["rxapIsEqualTo", "equalTo"] }, providers: [
            {
                provide: NG_VALIDATORS,
                multi: true,
                useExisting: forwardRef(() => IsEqualToDirective),
            },
        ], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: IsEqualToDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapIsEqualTo]',
                    providers: [
                        {
                            provide: NG_VALIDATORS,
                            multi: true,
                            useExisting: forwardRef(() => IsEqualToDirective),
                        },
                    ],
                    standalone: true,
                }]
        }], propDecorators: { equalTo: [{
                type: Input,
                args: [{
                        required: true,
                        alias: 'rxapIsEqualTo',
                    }]
            }] } });

var FormSystemMetadataKeys;
(function (FormSystemMetadataKeys) {
    FormSystemMetadataKeys["COMPONENTS"] = "rxap/form-system/components";
    FormSystemMetadataKeys["DATA_SOURCES"] = "rxap/form-system/data-sources";
    FormSystemMetadataKeys["COMPONENTS_PROPERTIES"] = "rxap/form-system/components-properties";
    FormSystemMetadataKeys["FORM_COMPONENT"] = "rxap/window-form-system/form-component";
})(FormSystemMetadataKeys || (FormSystemMetadataKeys = {}));

function UseDataSource(dataSource, name, settings) {
    return function (target, propertyKey) {
        const value = {
            dataSource,
            settings,
        };
        setMetadataMapMap(propertyKey, name, value, FormSystemMetadataKeys.DATA_SOURCES, target);
    };
}

class ExtractControlMixin {
    extractControl(ngControl = this.ngControl ??
        this.matFormField?._control?.ngControl ??
        null) {
        if (!ngControl) {
            throw new Error('The ngControl is not defined!');
        }
        this.ngControl = ngControl;
        const control = this.ngControl.control;
        if (!(control instanceof RxapFormControl)) {
            throw new Error('Control is not a RxapFormControl!');
        }
        return this.control = control;
    }
}

class RxapFormSystemError extends RxapError {
    constructor(message, code, className) {
        super('@rxap/form-system', message, code, className);
    }
}

class ExtractDataSourcesMixin {
    extractDataSources(formDefinition, controlId) {
        const map = getMetadata(FormSystemMetadataKeys.DATA_SOURCES, Object.getPrototypeOf(formDefinition));
        if (!map) {
            throw new RxapFormSystemError('Could not extract the use data source map from the form definition instance', '');
        }
        if (!map.has(controlId)) {
            throw new RxapFormSystemError('A use data source definition does not exists in the form definition metadata', '');
        }
        return map.get(controlId);
    }
}

class ExtractFormDefinitionMixin {
    // TODO : change to AbstractControl from @rxap/forms
    extractFormDefinition(control) {
        const formDefinition = control.rxapFormDefinition;
        if (!formDefinition) {
            throw new RxapFormSystemError('Could not find the form definition instance', '');
        }
        return formDefinition;
    }
}

const DATA_SOURCE_NAME = 'options';
function ComposeOptionsTransformers(...fnc) {
    return base => fnc.reduce((source, transform) => transform(source), base);
}
function UseOptionsDataSource(dataSource, settings) {
    return function (target, propertyKey) {
        UseDataSource(dataSource, DATA_SOURCE_NAME, settings)(target, propertyKey);
    };
}
let ExtractOptionsDataSourceMixin = class ExtractOptionsDataSourceMixin {
    extractOptionsDatasource(control) {
        control ??= this.extractControl();
        if (!(control instanceof RxapFormControl)) {
            throw new Error('Ensure to use a RxapFromControl');
        }
        const formDefinition = this.extractFormDefinition(control);
        const useDataSourceValueMap = this.extractDataSources(formDefinition, control.controlId);
        if (!useDataSourceValueMap.has('options')) {
            throw new Error(`The data source with the name 'options' is not defined`);
        }
        const useDataSourceValue = this.useDataSourceValue = useDataSourceValueMap.get('options');
        this.settings = this.useDataSourceValue.settings ?? {};
        let dataSource;
        try {
            dataSource = this.dataSourceLoader.load(useDataSourceValue.dataSource, this.metadata, this.injector);
        }
        catch (e) {
            if (e.name && e.name === 'NullInjectorError') {
                if (isDevMode()) {
                    console.error('Cloud not inject the options data source', this.useDataSourceValue);
                }
                throw new Error('Cloud not inject the options data source:\n' + e.message);
            }
            throw e;
        }
        if (this.settings?.transformer) {
            dataSource = new PipeDataSource(dataSource, map(this.settings.transformer), tap(options => useDataSourceValue.lastValue = options));
        }
        else {
            dataSource = new PipeDataSource(dataSource, tap(options => useDataSourceValue.lastValue = options));
        }
        return this.dataSource = dataSource;
    }
};
ExtractOptionsDataSourceMixin = __decorate([
    Mixin(ExtractControlMixin, ExtractFormDefinitionMixin, ExtractDataSourcesMixin)
], ExtractOptionsDataSourceMixin);

let IsSelectableValueDirective = class IsSelectableValueDirective {
    constructor(dataSourceLoader, injector) {
        this.dataSourceLoader = dataSourceLoader;
        this.injector = injector;
        this.viewer = { id: '[rxapIsSelectableValue]' };
    }
    validate(control) {
        if (control.value) {
            this.extractOptionsDatasource(control);
            const data = this.useDataSourceValue?.lastValue;
            if (data) {
                let options;
                if (Array.isArray(data)) {
                    options = data;
                }
                else {
                    options = Object.entries(data)
                        .map(([value, display]) => ({
                        value,
                        display,
                    }));
                }
                if (!options.some(option => option.value === control.value)) {
                    return {
                        isSelectableValue: {
                            expected: 'Value should be from the list of provided options',
                        },
                    };
                }
            }
            else if (isDevMode()) {
                console.warn('The last value from the OptionsDataSource is empty', this);
            }
        }
        return null;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: IsSelectableValueDirective, deps: [{ token: DataSourceLoader }, { token: INJECTOR }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: IsSelectableValueDirective, isStandalone: true, selector: "[rxapIsSelectableValue]", inputs: { viewer: "viewer" }, providers: [
            {
                provide: NG_VALIDATORS,
                multi: true,
                useExisting: forwardRef(() => IsSelectableValueDirective),
            },
        ], ngImport: i0 }); }
};
IsSelectableValueDirective = __decorate([
    Mixin(ExtractOptionsDataSourceMixin),
    __metadata("design:paramtypes", [DataSourceLoader,
        Injector])
], IsSelectableValueDirective);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: IsSelectableValueDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapIsSelectableValue]',
                    providers: [
                        {
                            provide: NG_VALIDATORS,
                            multi: true,
                            useExisting: forwardRef(() => IsSelectableValueDirective),
                        },
                    ],
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i1.DataSourceLoader, decorators: [{
                    type: Inject,
                    args: [DataSourceLoader]
                }] }, { type: i0.Injector, decorators: [{
                    type: Inject,
                    args: [INJECTOR]
                }] }], propDecorators: { viewer: [{
                type: Input
            }] } });

function ResolveByUuidParameter({ value }) {
    return {
        parameters: {
            uuid: value,
        },
    };
}
function ResolveByUuidResultFactory(transformer) {
    return (entity) => {
        return transformer(entity);
    };
}

function ApplyUseMethodAdapters(injector, method, config) {
    if (config?.adapter?.result || config?.adapter?.parameter) {
        return ToMethod((parameter, ...args) => {
            return new Promise((resolve, reject) => {
                runInInjectionContext(injector, () => {
                    parameter = config?.adapter?.parameter?.(parameter) ?? parameter;
                    const result = method.call(parameter, ...args);
                    if (isPromiseLike(result)) {
                        const p = result.then((result) => {
                            resolve(config?.adapter?.result?.(result) ?? result);
                        });
                        if (isPromise(p)) {
                            p.catch(reject);
                        }
                    }
                    else {
                        try {
                            resolve(config?.adapter?.result?.(result) ?? result);
                        }
                        catch (e) {
                            reject(e);
                        }
                    }
                });
            });
        });
    }
    return method;
}

class ExtractControlFromParentMixin {
    extractControlFromParent(parent, controlPath) {
        if (!controlPath) {
            throw new RxapFormSystemError('The control path is empty', '');
        }
        if (!parent.control) {
            throw new RxapFormSystemError('The control property of ControlContainer is not defined', '');
        }
        const control = parent.control.get(controlPath);
        if (!control) {
            throw new RxapFormSystemError('Could not find the control instance', '');
        }
        if (!(control instanceof RxapFormControl) &&
            !(control instanceof RxapFormGroup) &&
            !(control instanceof RxapFormArray)) {
            throw new RxapFormSystemError('The extracted control is not a RxapFormControl', '');
        }
        return control;
    }
}

const RXAP_USE_METHOD = 'rxap/form-system/method/use';
function UseMethod(method, name, config) {
    return function (target, propertyKey) {
        setMetadataMapMap(propertyKey, name, { method, config }, RXAP_USE_METHOD, target);
    };
}
class ExtractMethodsMixin {
    extractMethods(formDefinition, controlId) {
        const map = getMetadata(RXAP_USE_METHOD, Object.getPrototypeOf(formDefinition));
        if (!map) {
            console.log(map);
            throw new Error('Could not extract the use remote method map from the form definition instance');
        }
        if (!map.has(controlId)) {
            throw new Error('A use remote method definition does not exists in the form definition metadata');
        }
        return map.get(controlId);
    }
}

let ExtractMethodMixin = class ExtractMethodMixin {
    extractMethod(formDefinition, controlId, name) {
        const map = this.extractMethods(formDefinition, controlId);
        if (!map.has(name)) {
            throw new Error(`A method with the name '${name}' is not attached to the control '${controlId}' use the @UseMethod decorator to attach a method to the control`);
        }
        const { method: methodToken, config } = map.get(name);
        const method = this.injector.get(methodToken);
        return ApplyUseMethodAdapters(this.injector, method, config);
    }
};
ExtractMethodMixin = __decorate([
    Mixin(ExtractMethodsMixin)
], ExtractMethodMixin);

const OPTIONS_METHOD_NAME = 'options';
function UseOptionsMethod(method, config) {
    return function (target, propertyKey) {
        UseMethod(method, OPTIONS_METHOD_NAME, config)(target, propertyKey);
    };
}
let ExtractOptionsMethodMixin = class ExtractOptionsMethodMixin {
    extractOptionsMethod(control = this.extractControl(), formDefinition = this.extractFormDefinition(control)) {
        return this.extractMethod(formDefinition, control.controlId, OPTIONS_METHOD_NAME);
    }
};
ExtractOptionsMethodMixin = __decorate([
    Mixin(ExtractFormDefinitionMixin, ExtractMethodMixin, ExtractControlMixin)
], ExtractOptionsMethodMixin);

const RESOLVE_METHOD_NAME = 'resolve';
function UseResolveMethod(method, config) {
    return function (target, propertyKey) {
        UseMethod(method, RESOLVE_METHOD_NAME, config)(target, propertyKey);
    };
}
let ExtractResolveMethodMixin = class ExtractResolveMethodMixin {
    extractResolveMethod(control = this.extractControl(), formDefinition = this.extractFormDefinition(control)) {
        return this.extractMethod(formDefinition, control.controlId, RESOLVE_METHOD_NAME);
    }
};
ExtractResolveMethodMixin = __decorate([
    Mixin(ExtractFormDefinitionMixin, ExtractMethodMixin, ExtractControlMixin)
], ExtractResolveMethodMixin);

// TODO : move to rxap packages
class ForFormArrayItemsDirective {
    constructor(container, template, viewContainerRef, cdr) {
        this.container = container;
        this.template = template;
        this.viewContainerRef = viewContainerRef;
        this.cdr = cdr;
    }
    ngAfterViewInit() {
        if (this.container.control instanceof RxapFormArray) {
            this.formArray = this.container.control;
            this.container.control.value$.pipe(debounceTime(100), map$1(value => value.length), distinctUntilChanged(), startWith(0), pairwise(), tap$1(([a, b]) => {
                if (a !== b) {
                    this.render(b);
                }
            })).subscribe();
        }
        else {
            throw new Error('The control container is not an instance of RxapFormArray');
        }
    }
    ngOnDestroy() {
        this._formArrayValueSubscription?.unsubscribe();
    }
    render(length) {
        this.viewContainerRef.clear();
        for (let index = 0; index < length; index++) {
            const group = this.formArray.at(index);
            if (group instanceof UntypedFormGroup) {
                this.viewContainerRef.createEmbeddedView(this.template, {
                    $implicit: group,
                    index,
                    first: index === 0,
                    last: index === length - 1,
                    even: index % 2 === 0,
                    odd: index % 2 !== 0,
                    array: this.formArray,
                });
            }
            else {
                throw new Error('rxapForFormArrayItem only support FormArray with FormGroup as items');
            }
        }
        this.cdr.detectChanges();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ForFormArrayItemsDirective, deps: [{ token: i1$1.ControlContainer, skipSelf: true }, { token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: ForFormArrayItemsDirective, isStandalone: true, selector: "[rxapForFormArrayItem]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ForFormArrayItemsDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapForFormArrayItem]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i1$1.ControlContainer, decorators: [{
                    type: SkipSelf
                }] }, { type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });

// TODO : move to rxap packages
class FormArrayAddItemButtonDirective {
    constructor(parent, matButton) {
        this.parent = parent;
        this.matButton = matButton;
        this.type = 'button';
    }
    get disabled() {
        return this.isDisabled;
    }
    get isDisabled() {
        return !!this.formArray?.disabled;
    }
    ngAfterViewInit() {
        if (this.parent.control instanceof RxapFormArray) {
            this.formArray = this.parent.control;
        }
        if (this.matButton) {
            this._controlDisabledSubscription = this.formArray.disabled$.pipe(tap$1(isDisabled => this.matButton.disabled = isDisabled)).subscribe();
        }
    }
    ngOnDestroy() {
        this._controlDisabledSubscription?.unsubscribe();
    }
    onClick() {
        this.formArray.insertAt();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayAddItemButtonDirective, deps: [{ token: i1$1.ControlContainer, optional: true, skipSelf: true }, { token: i2.MatButton, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: FormArrayAddItemButtonDirective, isStandalone: true, selector: "[rxapFormArrayItemAddButton]", host: { listeners: { "click": "onClick()" }, properties: { "type": "this.type", "disabled": "this.disabled" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayAddItemButtonDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapFormArrayItemAddButton]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i1$1.ControlContainer, decorators: [{
                    type: Optional
                }, {
                    type: SkipSelf
                }] }, { type: i2.MatButton, decorators: [{
                    type: Optional
                }] }], propDecorators: { type: [{
                type: HostBinding,
                args: ['type']
            }], disabled: [{
                type: HostBinding,
                args: ['disabled']
            }], onClick: [{
                type: HostListener,
                args: ['click']
            }] } });

// TODO : move to rxap packages
class FormArrayItemButton {
    constructor(parent, matButton, renderer, elementRef) {
        this.parent = parent;
        this.matButton = matButton;
        this.renderer = renderer;
        this.elementRef = elementRef;
        this.type = 'button';
    }
    get disabled() {
        return this.isDisabled;
    }
    get isDeleted() {
        return this.deletedControl.value;
    }
    get index() {
        return this.formGroup.parent.controls.findIndex(control => control === this.formGroup);
    }
    get isDisabled() {
        return !!this.formGroup?.parent?.disabled;
    }
    ngAfterViewInit() {
        if (this.parent.control instanceof RxapFormGroup) {
            this.formGroup = this.parent.control;
            if (this.formGroup.controls.deleted instanceof RxapFormControl) {
                this.deletedControl = this.formGroup.controls.deleted;
            }
            else {
                this.deletedControl = new RxapFormControl(false, { controlId: 'deleted' });
                this.formGroup.addControl('deleted', this.deletedControl);
            }
            if (!(this.formGroup.parent instanceof UntypedFormArray)) {
                throw new Error(`The parent of the FormGroup is not a FormArray instance`);
            }
        }
        else {
            throw new Error(`The parent is not a form group instance`);
        }
        if (this.matButton) {
            this._controlDisabledSubscription = this.formGroup.disabled$.pipe(tap$1(isDisabled => this.matButton.disabled = isDisabled)).subscribe();
        }
        this.deletedControl.value$.pipe(tap$1(() => this.updateDisplayStyle())).subscribe();
    }
    ngOnDestroy() {
        this._controlDisabledSubscription?.unsubscribe();
        this._deletedControlValueSubscription?.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayItemButton, deps: [{ token: i1$1.ControlContainer, skipSelf: true }, { token: i2.MatButton, optional: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: FormArrayItemButton, host: { properties: { "type": "this.type", "disabled": "this.disabled" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayItemButton, decorators: [{
            type: Directive
        }], ctorParameters: () => [{ type: i1$1.ControlContainer, decorators: [{
                    type: SkipSelf
                }] }, { type: i2.MatButton, decorators: [{
                    type: Optional
                }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { type: [{
                type: HostBinding,
                args: ['type']
            }], disabled: [{
                type: HostBinding,
                args: ['disabled']
            }] } });

// TODO : move to rxap packages
class FormArrayItemRemoveButtonDirective extends FormArrayItemButton {
    onClick() {
        this.deletedControl.setValue(true);
    }
    updateDisplayStyle() {
        if (this.isDeleted) {
            this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'none');
        }
        else {
            this.renderer.removeStyle(this.elementRef.nativeElement, 'display');
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayItemRemoveButtonDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: FormArrayItemRemoveButtonDirective, isStandalone: true, selector: "button[rxapFormArrayItemRemoveButton]", host: { listeners: { "click": "onClick()" } }, usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayItemRemoveButtonDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'button[rxapFormArrayItemRemoveButton]',
                    standalone: true,
                }]
        }], propDecorators: { onClick: [{
                type: HostListener,
                args: ['click']
            }] } });

// TODO : move to rxap packages
class FormArrayItemRestoreButtonDirective extends FormArrayItemButton {
    onClick() {
        this.formGroup.controls.deleted.setValue(false);
    }
    updateDisplayStyle() {
        if (this.isDeleted) {
            this.renderer.removeStyle(this.elementRef.nativeElement, 'display');
        }
        else {
            this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'none');
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayItemRestoreButtonDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: FormArrayItemRestoreButtonDirective, isStandalone: true, selector: "button[rxapFormArrayItemRestoreButton]", host: { listeners: { "click": "onClick()" } }, usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayItemRestoreButtonDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'button[rxapFormArrayItemRestoreButton]',
                    standalone: true,
                }]
        }], propDecorators: { onClick: [{
                type: HostListener,
                args: ['click']
            }] } });

// TODO : move to rxap packages
class FormArrayRemovableDirective {
    constructor(parent) {
        this.parent = parent;
    }
    get isDeleted() {
        return this.deletedControl.value;
    }
    get isDisabled() {
        return !!this.control?.parent?.disabled;
    }
    ngAfterViewInit() {
        if (this.parent.control instanceof RxapFormGroup) {
            this.control = this.parent.control;
            if (this.control.controls.deleted instanceof RxapFormControl) {
                this.deletedControl = this.control.controls.deleted;
            }
            else {
                throw new Error(`The parent FormGroup instance does not have a 'deleted' control`);
            }
            if (!(this.control.parent instanceof UntypedFormArray)) {
                throw new Error(`The parent of the FormGroup is not a FormArray instance`);
            }
        }
        else {
            throw new Error(`The parent is not a form group instance`);
        }
        this._deletedControlValueSubscription = this.deletedControl.value$.pipe(tap$1((isDeleted) => {
            for (const [name, control] of Object.entries(this.control.controls)) {
                if (name !== 'deleted') {
                    if (isDeleted) {
                        control.disable({ onlySelf: true });
                    }
                    else if (!this.isDisabled) {
                        control.enable({ onlySelf: true });
                    }
                }
            }
        })).subscribe();
    }
    ngOnDestroy() {
        this._deletedControlValueSubscription?.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayRemovableDirective, deps: [{ token: i1$1.ControlContainer, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: FormArrayRemovableDirective, isStandalone: true, selector: "[rxapFormArrayRemovable]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormArrayRemovableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapFormArrayRemovable]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i1$1.ControlContainer, decorators: [{
                    type: Optional
                }] }] });

const RXAP_FORM_SYSTEM_SHOW_METADATA = 'rxap/form-system/show-function';
const RXAP_FORM_SYSTEM_HIDE_METADATA = 'rxap/form-system/hide-function';
const RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS = 'rxap/form-system/hide-show-options';
function UseHideFunction(hideFunction, options = {}) {
    return function (target, propertyKey) {
        setMetadataMap(propertyKey, hideFunction, RXAP_FORM_SYSTEM_HIDE_METADATA, target);
        if (Object.keys(options).length) {
            setMetadataMap(propertyKey, options, RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS, target);
        }
    };
}
function UseShowFunction(showFunction, options = {}) {
    return function (target, propertyKey) {
        setMetadataMap(propertyKey, showFunction, RXAP_FORM_SYSTEM_SHOW_METADATA, target);
        if (Object.keys(options).length) {
            setMetadataMap(propertyKey, options, RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS, target);
        }
    };
}
let ControlHideShowDirective = class ControlHideShowDirective {
    constructor(renderer, elementRef, parent, ngControl) {
        this.renderer = renderer;
        this.elementRef = elementRef;
        this.parent = parent;
        this.ngControl = ngControl;
        this.subscription = new Subscription();
    }
    ngOnInit() {
        if (!this.ngControl && !this.parent) {
            throw new Error('Easier the ControlContainer or NgControl must be injectable');
        }
        if (!this.ngControl && !this.controlId) {
            throw new Error('If the NgControl is not injectable then the control id must be defined!');
        }
        const control = this.ngControl?.control ?? this.extractControlFromParent(this.parent, this.controlId);
        if (!(control instanceof RxapFormControl)) {
            throw new Error('The control is not an instance of RxapFormControl');
        }
        this.control = control;
        const formDefinition = this.extractFormDefinition(control);
        const hideFunction = this.extractHideFunction(formDefinition);
        const showFunction = this.extractShowFunction(formDefinition);
        const options = this.extractOptions(formDefinition);
        let changeTrigger = formDefinition.rxapFormGroup.valueChanges;
        if (options.rootChange) {
            changeTrigger = formDefinition.rxapFormGroup.root.valueChanges;
        }
        changeTrigger = changeTrigger.pipe(startWith$1(null));
        if (showFunction) {
            this.subscription.add(changeTrigger.pipe(tap(() => {
                // TODO : resubscribe if the showFunction throws an error
                const show = showFunction.call(formDefinition, control);
                switch (show) {
                    case true:
                        this.show();
                        break;
                    case false:
                        this.hide();
                        break;
                    case null:
                        this.reset();
                        break;
                }
            }), catchError(err => {
                console.error(err);
                return of(null);
            })).subscribe());
        }
        if (hideFunction) {
            this.subscription.add(changeTrigger.pipe(tap(() => {
                // TODO : resubscribe if the hideFunction throws an error
                const hide = hideFunction.call(formDefinition, control);
                switch (hide) {
                    case true:
                        this.hide();
                        break;
                    case false:
                        this.show();
                        break;
                    case null:
                        this.reset();
                        break;
                }
            }), catchError(err => {
                console.error(err);
                return of(null);
            })).subscribe());
        }
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    extractOptions(formDefinition) {
        const map = getMetadata(RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS, Object.getPrototypeOf(formDefinition)) ?? null;
        if (!map || !map.has(this.control.controlId)) {
            return {};
        }
        return map.get(this.control.controlId);
    }
    extractHideFunction(formDefinition) {
        const map = getMetadata(RXAP_FORM_SYSTEM_HIDE_METADATA, Object.getPrototypeOf(formDefinition)) ?? null;
        if (!map || !map.has(this.control.controlId)) {
            return null;
        }
        return map.get(this.control.controlId);
    }
    extractShowFunction(formDefinition) {
        const map = getMetadata(RXAP_FORM_SYSTEM_SHOW_METADATA, Object.getPrototypeOf(formDefinition)) ?? null;
        if (!map || !map.has(this.control.controlId)) {
            return null;
        }
        return map.get(this.control.controlId);
    }
    hide() {
        this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'none');
    }
    show() {
        this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'block');
    }
    reset() {
        this.renderer.removeStyle(this.elementRef.nativeElement, 'display');
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ControlHideShowDirective, deps: [{ token: Renderer2 }, { token: ElementRef }, { token: ControlContainer, optional: true }, { token: NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: ControlHideShowDirective, isStandalone: true, selector: "[rxapControlHideShow]", inputs: { controlId: ["rxapControlHideShow", "controlId"] }, ngImport: i0 }); }
};
ControlHideShowDirective = __decorate([
    Mixin(ExtractControlFromParentMixin, ExtractFormDefinitionMixin),
    __metadata("design:paramtypes", [Renderer2,
        ElementRef, Object, Object])
], ControlHideShowDirective);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ControlHideShowDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapControlHideShow]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2, decorators: [{
                    type: Inject,
                    args: [Renderer2]
                }] }, { type: i0.ElementRef, decorators: [{
                    type: Inject,
                    args: [ElementRef]
                }] }, { type: i1$1.ControlContainer, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [ControlContainer]
                }] }, { type: i1$1.NgControl, decorators: [{
                    type: Self
                }, {
                    type: Optional
                }, {
                    type: Inject,
                    args: [NgControl]
                }] }], propDecorators: { controlId: [{
                type: Input,
                args: ['rxapControlHideShow']
            }] } });

let InputSelectOptionsDirective = class InputSelectOptionsDirective {
    constructor(template, dataSourceLoader, viewContainerRef, injector, cdr, 
    // The ngControl could be unknown on construction
    // bc it is available after the content is init
    ngControl = null, matFormField = null) {
        this.template = template;
        this.dataSourceLoader = dataSourceLoader;
        this.viewContainerRef = viewContainerRef;
        this.injector = injector;
        this.cdr = cdr;
        this.ngControl = ngControl;
        this.matFormField = matFormField;
        this.viewer = { id: '[rxapInputSelectOptions]' };
        this.subscription = new Subscription();
        this.options = null;
        /**
         * This flag is used to prevent the setValue is called for each refresh
         * of the options list. This is needed because the setValue method will
         * trigger a new refresh of the options list. This results in an endless
         * call stack. This flag is set to true if the setValue method is called
         * once.
         */
        this.isAutocompleteToDisplayTriggered = false;
    }
    ngAfterViewInit() {
        this.extractOptionsDatasource();
        this.viewer = {
            id: '[rxapInputSelectOptions]' + this.control.controlId,
            viewChange: this.settings?.loadOnce ? EMPTY : this.control.value$.pipe(throttleTime(1000), distinctUntilChanged$1((a, b) => equals(a, b)), map(value => {
                if (this.settings?.ignoreSelectedValue) {
                    return {};
                }
                return value;
            })),
            control: this.control,
        };
        if (this.matAutocomplete) {
            this.matAutocomplete.displayWith = this.toDisplay.bind(this);
            this.settings ??= {};
            this.settings.filteredOptions ??= true;
        }
        this.loadOptions();
    }
    toDisplay(value) {
        if (!value) {
            return '';
        }
        return this.options?.find((option) => option.value === value)?.display ??
            (isDevMode() ? 'to display error' : '');
    }
    ngOnDestroy() {
        this.subscription?.unsubscribe();
    }
    loadOptions(dataSource = this.dataSource) {
        this.subscription.add(dataSource.connect(this.viewer).pipe(switchMap(options => {
            if (this.settings?.filteredOptions) {
                return this.control.value$.pipe(map(controlValue => {
                    if (typeof controlValue === 'string' && controlValue) {
                        controlValue = controlValue.toLowerCase();
                        if (Array.isArray(options)) {
                            return options.filter(option => option.display.toLowerCase().includes(controlValue));
                        }
                        else {
                            return Object.entries(options)
                                .filter(([value, display]) => typeof display ===
                                'string' &&
                                display.toLowerCase().includes(controlValue))
                                .map(([value, display]) => ({
                                value,
                                display,
                            }));
                        }
                    }
                    return options;
                }));
            }
            return of(options);
        }), tap(options => this.renderTemplate(this.options = options)), tap(() => {
            if (this.matAutocomplete && !this.isAutocompleteToDisplayTriggered) {
                this.isAutocompleteToDisplayTriggered = true;
                // trigger a change detection after the options are rendered
                // this is needed to trigger the mat-autocomplete options to display function
                this.ngControl?.control?.setValue(this.ngControl?.control?.value);
            }
        })).subscribe());
    }
    renderTemplate(options = this.options) {
        this.viewContainerRef.clear();
        if (options) {
            if (!Array.isArray(options)) {
                for (const [value, display] of Object.entries(options)) {
                    this.viewContainerRef.createEmbeddedView(this.template, {
                        $implicit: {
                            value,
                            display,
                        },
                    });
                }
            }
            else {
                for (const option of options) {
                    this.viewContainerRef.createEmbeddedView(this.template, { $implicit: option });
                }
            }
        }
        else {
            if (isDevMode()) {
                console.warn(`The options for the control ${this.control.fullControlPath} is empty/null/undefined!`);
            }
        }
        this.cdr.detectChanges();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: InputSelectOptionsDirective, deps: [{ token: TemplateRef }, { token: DataSourceLoader }, { token: ViewContainerRef }, { token: INJECTOR }, { token: ChangeDetectorRef }, { token: NgControl, optional: true }, { token: MAT_FORM_FIELD, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: InputSelectOptionsDirective, isStandalone: true, selector: "[rxapInputSelectOptions]", inputs: { viewer: ["rxapInputSelectOptionsViewer", "viewer"], metadata: ["rxapInputSelectOptionsMetadata", "metadata"], matAutocomplete: ["rxapInputSelectOptionsMatAutocomplete", "matAutocomplete"] }, ngImport: i0 }); }
};
InputSelectOptionsDirective = __decorate([
    Mixin(ExtractOptionsDataSourceMixin),
    __metadata("design:paramtypes", [TemplateRef,
        DataSourceLoader,
        ViewContainerRef,
        Injector,
        ChangeDetectorRef, Object, Object])
], InputSelectOptionsDirective);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: InputSelectOptionsDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapInputSelectOptions]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i0.TemplateRef, decorators: [{
                    type: Inject,
                    args: [TemplateRef]
                }] }, { type: i1.DataSourceLoader, decorators: [{
                    type: Inject,
                    args: [DataSourceLoader]
                }] }, { type: i0.ViewContainerRef, decorators: [{
                    type: Inject,
                    args: [ViewContainerRef]
                }] }, { type: i0.Injector, decorators: [{
                    type: Inject,
                    args: [INJECTOR]
                }] }, { type: i0.ChangeDetectorRef, decorators: [{
                    type: Inject,
                    args: [ChangeDetectorRef]
                }] }, { type: i1$1.NgControl, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [NgControl]
                }] }, { type: i3.MatFormField, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [MAT_FORM_FIELD]
                }] }], propDecorators: { viewer: [{
                type: Input,
                args: ['rxapInputSelectOptionsViewer']
            }], metadata: [{
                type: Input,
                args: ['rxapInputSelectOptionsMetadata']
            }], matAutocomplete: [{
                type: Input,
                args: ['rxapInputSelectOptionsMatAutocomplete']
            }] } });

class FormSystemDirectivesModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormSystemDirectivesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.0.6", ngImport: i0, type: FormSystemDirectivesModule, imports: [InputSelectOptionsDirective,
            ControlHideShowDirective], exports: [InputSelectOptionsDirective,
            ControlHideShowDirective] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormSystemDirectivesModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormSystemDirectivesModule, decorators: [{
            type: NgModule,
            args: [{
                    exports: [
                        InputSelectOptionsDirective,
                        ControlHideShowDirective,
                    ],
                    imports: [
                        InputSelectOptionsDirective,
                        ControlHideShowDirective,
                    ],
                }]
        }] });

let OptionsFromMethodDirective = class OptionsFromMethodDirective {
    constructor() {
        this.options = null;
        this.ngControl = null;
        this.matFormField = null;
        this.settings = {};
        this.viewContainerRef = inject(ViewContainerRef);
        this.injector = inject(INJECTOR);
        this.cdr = inject(ChangeDetectorRef);
        this.template = inject(TemplateRef);
    }
    static ngTemplateContextGuard(dir, ctx) {
        return true;
    }
    async ngAfterViewInit() {
        this.ngControl = this.injector.get(NgControl, null);
        this.matFormField = this.injector.get(MatFormField, null);
        this.method = this.extractOptionsMethod();
        // ensure that the options are loaded. It is possible that the ngOnChange is triggered before the ngAfterViewInit
        // then the options are not loaded.
        if (!this.options) {
            this.setOptions(await this.loadOptions(this.parameters));
        }
    }
    async ngOnChanges(changes) {
        // only try to load the options if the method is defined
        // else the initial load will be triggered in the ngAfterViewInit
        if (!this.method) {
            console.debug('The method is not yet defined');
            return;
        }
        const parametersChanges = changes['parameters'];
        if (parametersChanges) {
            this.setOptions(await this.loadOptions(parametersChanges.currentValue));
        }
    }
    async loadOptions(parameters) {
        return this.method.call(parameters);
    }
    renderTemplate() {
        if (!this.options) {
            throw new Error('The options are not yet loaded');
        }
        this.viewContainerRef.clear();
        for (const option of this.options) {
            this.viewContainerRef.createEmbeddedView(this.template, { $implicit: option });
        }
        if (this.resetOnChange !== undefined) {
            this.control?.reset(this.resetOnChange);
        }
        this.cdr.detectChanges();
    }
    setOptions(options) {
        this.options = options.slice();
        this.renderTemplate();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: OptionsFromMethodDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: OptionsFromMethodDirective, isStandalone: true, selector: "[rxapOptionsFromMethod]", inputs: { parameters: ["rxapOptionsFromMethodParameters", "parameters"], resetOnChange: ["rxapOptionsFromMethodResetOnChange", "resetOnChange"] }, usesOnChanges: true, ngImport: i0 }); }
};
OptionsFromMethodDirective = __decorate([
    Mixin(ExtractOptionsMethodMixin)
], OptionsFromMethodDirective);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: OptionsFromMethodDirective, decorators: [{
            type: Directive,
            args: [{
                    // eslint-disable-next-line @angular-eslint/directive-selector
                    selector: '[rxapOptionsFromMethod]',
                    standalone: true,
                }]
        }], propDecorators: { parameters: [{
                type: Input,
                args: ['rxapOptionsFromMethodParameters']
            }], resetOnChange: [{
                type: Input,
                args: ['rxapOptionsFromMethodResetOnChange']
            }] } });

const REMOTE_METHOD_NAME = 'options';
const RXAP_USE_REMOTE_METHOD = 'rxap/form-system/remote-method/use';
function UseRemoteMethod(remoteMethod, name) {
    return function (target, propertyKey) {
        setMetadataMapMap(propertyKey, name, remoteMethod, RXAP_USE_REMOTE_METHOD, target);
    };
}
function UseOptionsRemoteMethod(dataSource) {
    return function (target, propertyKey) {
        UseRemoteMethod(dataSource, REMOTE_METHOD_NAME)(target, propertyKey);
    };
}
class ExtractRemoteMethodsMixin {
    extractRemoteMethods(formDefinition, controlId) {
        const map = getMetadata(RXAP_USE_REMOTE_METHOD, Object.getPrototypeOf(formDefinition));
        if (!map) {
            throw new RxapFormSystemError('Could not extract the use remote method map from the form definition instance', '');
        }
        if (!map.has(controlId)) {
            throw new RxapFormSystemError('A use remote method definition does not exists in the form definition metadata', '');
        }
        return map.get(controlId);
    }
}
let OptionsFromRemoteMethodDirective = class OptionsFromRemoteMethodDirective {
    constructor(ngControl, template, remoteMethodLoader, viewContainerRef, injector, cdr) {
        this.ngControl = ngControl;
        this.template = template;
        this.remoteMethodLoader = remoteMethodLoader;
        this.viewContainerRef = viewContainerRef;
        this.injector = injector;
        this.cdr = cdr;
        this.withoutParameters = false;
    }
    ngOnChanges(changes) {
        const parametersChanges = changes['parameters'];
        if (parametersChanges) {
            if (!this.remoteMethodToken) {
                this.remoteMethodToken = this.extractRemoteMethodToken();
            }
            this.renderTemplate(parametersChanges.currentValue);
        }
        if (changes['withoutParameters']?.currentValue) {
            if (!this.remoteMethodToken) {
                this.remoteMethodToken = this.extractRemoteMethodToken();
            }
            this.renderTemplate();
        }
    }
    extractRemoteMethodToken() {
        const control = this.ngControl.control;
        if (!(control instanceof RxapFormControl)) {
            throw new Error('Control is not a RxapFormControl!');
        }
        const formDefinition = this.extractFormDefinition(control);
        const remoteMethodsTokens = this.extractRemoteMethods(formDefinition, control.controlId);
        if (!remoteMethodsTokens.has(REMOTE_METHOD_NAME)) {
            throw new Error(`The remote method with the name 'options' is not defined`);
        }
        return remoteMethodsTokens.get(REMOTE_METHOD_NAME);
    }
    async renderTemplate(parameters) {
        const options = await this.remoteMethodLoader.call$(this.remoteMethodToken, parameters, undefined, this.injector);
        this.viewContainerRef.clear();
        for (const option of options) {
            this.viewContainerRef.createEmbeddedView(this.template, { $implicit: option });
        }
        if (this.resetOnChange !== undefined) {
            this.ngControl.reset(this.resetOnChange);
        }
        this.cdr.detectChanges();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: OptionsFromRemoteMethodDirective, deps: [{ token: NgControl }, { token: TemplateRef }, { token: RemoteMethodLoader }, { token: ViewContainerRef }, { token: INJECTOR }, { token: ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: OptionsFromRemoteMethodDirective, isStandalone: true, selector: "[rxapOptionsFromRemoteMethod]", inputs: { parameters: ["rxapOptionsFromRemoteMethodParameters", "parameters"], resetOnChange: ["rxapOptionsFromRemoteMethodResetOnChange", "resetOnChange"], withoutParameters: ["rxapOptionsFromRemoteMethodWithoutParameters", "withoutParameters"] }, usesOnChanges: true, ngImport: i0 }); }
};
OptionsFromRemoteMethodDirective = __decorate([
    Mixin(ExtractFormDefinitionMixin, ExtractRemoteMethodsMixin),
    __metadata("design:paramtypes", [NgControl,
        TemplateRef,
        RemoteMethodLoader,
        ViewContainerRef,
        Injector,
        ChangeDetectorRef])
], OptionsFromRemoteMethodDirective);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: OptionsFromRemoteMethodDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapOptionsFromRemoteMethod]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
                    type: Inject,
                    args: [NgControl]
                }] }, { type: i0.TemplateRef, decorators: [{
                    type: Inject,
                    args: [TemplateRef]
                }] }, { type: i2$1.RemoteMethodLoader, decorators: [{
                    type: Inject,
                    args: [RemoteMethodLoader]
                }] }, { type: i0.ViewContainerRef, decorators: [{
                    type: Inject,
                    args: [ViewContainerRef]
                }] }, { type: i0.Injector, decorators: [{
                    type: Inject,
                    args: [INJECTOR]
                }] }, { type: i0.ChangeDetectorRef, decorators: [{
                    type: Inject,
                    args: [ChangeDetectorRef]
                }] }], propDecorators: { parameters: [{
                type: Input,
                args: ['rxapOptionsFromRemoteMethodParameters']
            }], resetOnChange: [{
                type: Input,
                args: ['rxapOptionsFromRemoteMethodResetOnChange']
            }], withoutParameters: [{
                type: Input,
                args: ['rxapOptionsFromRemoteMethodWithoutParameters']
            }] } });

class TestNgControl extends NgControl {
    constructor(_control) {
        super();
        this._control = _control;
    }
    get control() {
        return this._control;
    }
    viewToModelUpdate(newValue) {
        throw new Error('Method not implemented.');
    }
}

function UseComponent(component, setProperties = {}) {
    return function (target, propertyKey) {
        setMetadataMap(propertyKey, component, FormSystemMetadataKeys.COMPONENTS, target);
        setMetadataMap(propertyKey, setProperties, FormSystemMetadataKeys.COMPONENTS_PROPERTIES, target);
    };
}

/**
 * Links a component with a form definition
 *
 * @param component
 */
function UseFormComponent(component) {
    return function (target) {
        setMetadata(FormSystemMetadataKeys.FORM_COMPONENT, component, target);
    };
}

const RXAP_FORM_CONTROL_SOURCE = new InjectionToken('rxap/forms/data-source');
class ControlDataSource extends BaseDataSource {
    constructor(control, metadata = null) {
        super(metadata);
        this.control = control;
    }
    init() {
        if (this._initialised) {
            return;
        }
        super.init();
        if (isDevMode()) {
            console.log(this.control);
        }
        this._data$ = this.control.valueChanges.pipe(startWith$1(this.control.value), distinctUntilChanged$1((a, b) => equals(a, b)), shareReplay(1));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ControlDataSource, deps: [{ token: RXAP_FORM_CONTROL_SOURCE }, { token: RXAP_DATA_SOURCE_METADATA, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ControlDataSource }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: ControlDataSource, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [RXAP_FORM_CONTROL_SOURCE]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_DATA_SOURCE_METADATA]
                }] }] });
function controlDataSource(control) {
    // TODO : remove as any (wait for @rxap/forms update)
    return new ControlDataSource(control, { id: control.controlId });
}

function FormContextFromActivatedRouteFactory(route) {
    return route.snapshot.params;
}

let FormSystemControlDirective = class FormSystemControlDirective {
    constructor(parent, cfr, viewContainerRef, dataSourceLoader, injector) {
        this.parent = parent;
        this.cfr = cfr;
        this.viewContainerRef = viewContainerRef;
        this.dataSourceLoader = dataSourceLoader;
        this.injector = injector;
    }
    ngOnInit() {
        this.control = this.extractControl();
        const formDefinition = this.extractFormDefinition();
        this.componentRef = this.createComponent(formDefinition);
        this.setDataSources(formDefinition, this.componentRef.instance);
        this.setComponentProperties(formDefinition, this.componentRef.instance);
        this.viewContainerRef.insert(this.componentRef.hostView);
    }
    registerOnChange(fn) {
        this.componentRef.instance.registerOnChange(fn);
    }
    registerOnTouched(fn) {
        this.componentRef.instance.registerOnTouched(fn);
    }
    writeValue(value) {
        this.componentRef.instance.writeValue(value);
    }
    setDisabledState(isDisabled) {
        if (this.componentRef.instance.setDisabledState) {
            this.componentRef.instance.setDisabledState(isDisabled);
        }
    }
    setDataSources(formDefinition, component) {
        if (!component.setDataSource) {
            throw new RxapFormSystemError('The ControlWithDataSource interface is not implemented for the control component, but the control has defined data sources', '');
        }
        const useDataSourceValueMap = this.extractDataSources(formDefinition, this.controlId);
        for (const [name, useDataSourceValue] of useDataSourceValueMap.entries()) {
            let dataSource = this.dataSourceLoader.load(useDataSourceValue.dataSource);
            const settings = useDataSourceValue.settings;
            if (settings?.transformer) {
                dataSource = new PipeDataSource(dataSource, map(settings.transformer));
            }
            component.setDataSource(name, dataSource, useDataSourceValue.settings);
        }
    }
    setComponentProperties(formDefinition, component) {
        const componentProperties = this.extractComponentProperties(formDefinition);
        for (const [key, value] of Object.entries(componentProperties)) {
            Reflect.set(component, key, value);
        }
    }
    createComponent(formDefinition) {
        const component = this.extractComponent(formDefinition);
        const componentFactory = this.cfr.resolveComponentFactory(component);
        return componentFactory.create(this.injector);
    }
    extractControl() {
        if (!this.parent.control) {
            throw new RxapFormSystemError('The control property of ControlContainer is not defined', '');
        }
        const control = this.parent.control.get(this.controlId);
        if (!control) {
            throw new RxapFormSystemError('Could not find the control instance', '');
        }
        if (!(control instanceof RxapFormControl)) {
            throw new RxapFormSystemError('The extracted control is not a RxapFormControl', '');
        }
        return control;
    }
    extractFormDefinition() {
        const formDefinition = this.control.rxapFormDefinition;
        if (!formDefinition) {
            throw new RxapFormSystemError('Could not find the form definition instance', '');
        }
        return formDefinition;
    }
    extractComponent(formDefinition) {
        const map = getMetadata(FormSystemMetadataKeys.COMPONENTS, Object.getPrototypeOf(formDefinition));
        if (!map) {
            throw new RxapFormSystemError('Could not extract the use component map from the form definition instance', '');
        }
        if (!map.has(this.controlId)) {
            throw new RxapFormSystemError('A use component definition does not exists in the form definition metadata', '');
        }
        return map.get(this.controlId);
    }
    extractComponentProperties(formDefinition) {
        const map = getMetadata(FormSystemMetadataKeys.COMPONENTS_PROPERTIES, Object.getPrototypeOf(formDefinition));
        if (!map) {
            throw new RxapFormSystemError('Could not extract the use component properties map from the form definition instance', '');
        }
        if (!map.has(this.controlId)) {
            throw new RxapFormSystemError('A use component definition does not exists in the form definition metadata', '');
        }
        return map.get(this.controlId);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormSystemControlDirective, deps: [{ token: ControlContainer }, { token: ComponentFactoryResolver }, { token: ViewContainerRef }, { token: DataSourceLoader }, { token: INJECTOR }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.6", type: FormSystemControlDirective, isStandalone: true, selector: "[rxapFormSystemControl]", inputs: { controlId: "controlId" }, ngImport: i0 }); }
};
FormSystemControlDirective = __decorate([
    Mixin(ExtractDataSourcesMixin),
    __metadata("design:paramtypes", [ControlContainer,
        ComponentFactoryResolver,
        ViewContainerRef,
        DataSourceLoader,
        Injector])
], FormSystemControlDirective);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: FormSystemControlDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[rxapFormSystemControl]',
                    standalone: true,
                }]
        }], ctorParameters: () => [{ type: i1$1.ControlContainer, decorators: [{
                    type: Inject,
                    args: [ControlContainer]
                }] }, { type: i0.ComponentFactoryResolver, decorators: [{
                    type: Inject,
                    args: [ComponentFactoryResolver]
                }] }, { type: i0.ViewContainerRef, decorators: [{
                    type: Inject,
                    args: [ViewContainerRef]
                }] }, { type: i1.DataSourceLoader, decorators: [{
                    type: Inject,
                    args: [DataSourceLoader]
                }] }, { type: i0.Injector, decorators: [{
                    type: Inject,
                    args: [INJECTOR]
                }] }], propDecorators: { controlId: [{
                type: Input,
                args: [{ required: true }]
            }] } });

const SUBMIT_CONTEXT_FORM_ADAPTER_METHOD = new InjectionToken('submit-context-form-adapter-method');
class SubmitContextFormAdapter extends ProxyRemoteMethod {
    constructor(remoteMethod, context) {
        super(remoteMethod);
        this.context = context;
    }
    transformParameters(value) {
        return {
            parameters: this.context ?? {},
            requestBody: value,
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: SubmitContextFormAdapter, deps: [{ token: SUBMIT_CONTEXT_FORM_ADAPTER_METHOD }, { token: RXAP_FORM_CONTEXT }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: SubmitContextFormAdapter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: SubmitContextFormAdapter, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [SUBMIT_CONTEXT_FORM_ADAPTER_METHOD]
                }] }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [RXAP_FORM_CONTEXT]
                }] }] });
function SubmitContextFormAdapterFactory(remoteMethod, context) {
    return new SubmitContextFormAdapter(remoteMethod, context);
}

// region validators
// endregion

/**
 * Generated bundle index. Do not edit.
 */

export { ApplyUseMethodAdapters, ComposeOptionsTransformers, ControlDataSource, ControlHideShowDirective, DATA_SOURCE_NAME, ExtractControlFromParentMixin, ExtractControlMixin, ExtractDataSourcesMixin, ExtractFormDefinitionMixin, ExtractMethodMixin, ExtractMethodsMixin, ExtractOptionsDataSourceMixin, ExtractOptionsMethodMixin, ExtractRemoteMethodsMixin, ExtractResolveMethodMixin, ForFormArrayItemsDirective, FormArrayAddItemButtonDirective, FormArrayItemButton, FormArrayItemRemoveButtonDirective, FormArrayItemRestoreButtonDirective, FormArrayRemovableDirective, FormContextFromActivatedRouteFactory, FormSystemControlDirective, FormSystemDirectivesModule, FormSystemMetadataKeys, InputSelectOptionsDirective, IsEqualToDirective, IsSelectableValueDirective, OPTIONS_METHOD_NAME, OptionsFromMethodDirective, OptionsFromRemoteMethodDirective, REMOTE_METHOD_NAME, RESOLVE_METHOD_NAME, RXAP_FORM_CONTROL_SOURCE, RXAP_FORM_SYSTEM_HIDE_METADATA, RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS, RXAP_FORM_SYSTEM_SHOW_METADATA, RXAP_USE_METHOD, RXAP_USE_REMOTE_METHOD, ResolveByUuidParameter, ResolveByUuidResultFactory, RxapFormSystemError, SUBMIT_CONTEXT_FORM_ADAPTER_METHOD, SubmitContextFormAdapter, SubmitContextFormAdapterFactory, TestNgControl, UseComponent, UseDataSource, UseFormComponent, UseHideFunction, UseMethod, UseOptionsDataSource, UseOptionsMethod, UseOptionsRemoteMethod, UseRemoteMethod, UseResolveMethod, UseShowFunction, controlDataSource };
//# sourceMappingURL=rxap-form-system.mjs.map
