import * as i4 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { Injectable, inject, input, model, signal, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output } from '@angular/core';
import { AXPopupService } from '@acorex/components/popup';
import * as i1 from '@acorex/platform/layout/widget-core';
import { AXPWidgetSerializationHelper, AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
import { cloneDeep, isNil, set, isEqual } from 'lodash-es';
import * as i2 from '@acorex/components/form';
import { AXFormComponent, AXFormModule } from '@acorex/components/form';
import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
import * as i1$1 from '@acorex/components/button';
import { AXButtonModule } from '@acorex/components/button';
import * as i2$1 from '@acorex/components/decorators';
import { AXDecoratorModule } from '@acorex/components/decorators';
import * as i3 from '@acorex/components/loading';
import { AXLoadingModule } from '@acorex/components/loading';
import { AXBasePageComponent } from '@acorex/components/page';
import * as i5 from '@acorex/core/translation';
import { AXTranslationModule } from '@acorex/core/translation';
import { AXPExpressionEvaluatorService } from '@acorex/platform/core';

class AXPLayoutConversionService {
    constructor() {
        //#region ----   Caching   ----
        this.widgetTreeCache = new Map();
        this.formDefinitionCache = new Map();
    }
    //#endregion
    //#region ----   Public Methods   ----
    /**
     * Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
     * Groups become Fieldset Layouts with Form Field widgets as children
     * Fields become Form Field widgets with Editor widgets as children
     */
    convertFormDefinition(formDefinition) {
        // Create cache key based on form definition content
        const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
        // Check cache first
        if (this.widgetTreeCache.has(cacheKey)) {
            return this.widgetTreeCache.get(cacheKey);
        }
        // Generate widget tree
        const widgetTree = {
            type: 'grid-layout',
            name: 'dynamic-form-container',
            mode: formDefinition.mode, // Preserve form-level mode
            options: {
                title: 'Dynamic Form',
                grid: {
                    default: {
                        columns: 1,
                        gap: '1rem',
                    },
                },
            },
            children: formDefinition.groups.map((group) => this.createGroupAsFieldsetWidget(group, formDefinition.mode)),
        };
        // Cache the result
        this.widgetTreeCache.set(cacheKey, widgetTree);
        return widgetTree;
    }
    /**
     * Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
     * Parses Fieldset Layouts back to Groups
     * Parses Form Field widgets back to Fields
     */
    convertWidgetTreeToFormDefinition(widgetTree) {
        // Create cache key based on widget tree content
        const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
        // Check cache first
        if (this.formDefinitionCache.has(cacheKey)) {
            return this.formDefinitionCache.get(cacheKey);
        }
        // Parse widget tree
        const groups = [];
        if (widgetTree.children) {
            widgetTree.children.forEach((child) => {
                if (child.type === 'fieldset-layout') {
                    const group = this.extractGroupFromFieldset(child);
                    groups.push(group);
                }
            });
        }
        const formDefinition = { groups };
        // Cache the result
        this.formDefinitionCache.set(cacheKey, formDefinition);
        return formDefinition;
    }
    /**
     * Validate that a widget tree represents a valid dynamic form structure
     */
    validateFormWidgetTree(widgetTree) {
        if (!widgetTree || widgetTree.type !== 'grid-layout') {
            return false;
        }
        if (!widgetTree.children || widgetTree.children.length === 0) {
            return true; // Empty form is valid
        }
        // Check that all children are fieldset-layout widgets
        return widgetTree.children.every((child) => child.type === 'fieldset-layout' &&
            child.children &&
            child.children.every((formField) => formField.type === 'form-field' && formField.children && formField.children.length > 0));
    }
    /**
     * Clear all caches
     */
    clearCaches() {
        this.widgetTreeCache.clear();
        this.formDefinitionCache.clear();
    }
    /**
     * Get cache statistics
     */
    getCacheStats() {
        return {
            widgetTreeCacheSize: this.widgetTreeCache.size,
            formDefinitionCacheSize: this.formDefinitionCache.size,
        };
    }
    //#endregion
    //#region ----   Private Methods   ----
    /**
     * Convert a single group to Fieldset widget structure
     */
    createGroupAsFieldsetWidget(group, formMode) {
        // Determine columns count from layout or default to 1
        const columnsCount = 1;
        // Use group mode if set, otherwise inherit from form mode
        const groupMode = group.mode || formMode;
        return {
            type: 'fieldset-layout',
            name: group.name,
            mode: groupMode,
            options: {
                title: group.title,
                description: group.description,
                cols: columnsCount,
                look: group.look || 'container', // Default to 'container' if not specified
            },
            children: this.createFieldWidgets(group.parameters, columnsCount, groupMode),
        };
    }
    /**
     * Convert fields to Form Field widgets
     */
    createFieldWidgets(fields, columnsCount, groupMode) {
        return fields.map((field) => this.createFormFieldWidget(field, groupMode));
    }
    /**
     * Convert a single field to Form Field widget with editor as child
     */
    createFormFieldWidget(field, groupMode) {
        // Use field mode if set, otherwise inherit from group mode
        const fieldMode = field.mode || groupMode;
        // Ensure the editor widget also has the mode set
        const editorWidget = { ...field.widget };
        if (!editorWidget.mode) {
            editorWidget.mode = fieldMode;
        }
        return {
            type: 'form-field',
            name: field.path,
            mode: fieldMode,
            options: {
                label: field.title,
                badge: field.badge,
                description: field.description,
                showLabel: true,
            },
            children: [editorWidget], // The editor widget becomes a child of form-field
        };
    }
    /**
     * Extract group information from Fieldset Layout widget
     */
    extractGroupFromFieldset(fieldsetNode) {
        const columnsCount = fieldsetNode.options?.['cols'] || 1;
        // Extract fields directly from fieldset children
        const fields = [];
        if (fieldsetNode.children) {
            fieldsetNode.children.forEach((formField) => {
                if (formField.type === 'form-field' && formField.children && formField.children.length > 0) {
                    const field = this.extractFieldFromFormWidget(formField);
                    if (field) {
                        fields.push(field);
                    }
                }
            });
        }
        return {
            name: fieldsetNode.name || `group-${Date.now()}`,
            title: fieldsetNode.options?.['title'],
            description: fieldsetNode.options?.['description'],
            parameters: fields,
            mode: fieldsetNode.mode,
            look: fieldsetNode.options?.['look'],
        };
    }
    /**
     * Extract field information from Form Field widget
     */
    extractFieldFromFormWidget(formFieldNode) {
        if (!formFieldNode.children || formFieldNode.children.length === 0) {
            return null;
        }
        const editorWidget = formFieldNode.children[0];
        return {
            path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
            title: formFieldNode.options?.['label'],
            badge: formFieldNode.options?.['badge'],
            description: formFieldNode.options?.['description'],
            widget: editorWidget,
            mode: formFieldNode.mode,
        };
    }
    /**
     * Create cache key for form definition
     */
    createFormDefinitionCacheKey(formDefinition) {
        // Create a hash-like key instead of full JSON string
        const keyParts = [];
        keyParts.push(`groups:${formDefinition.groups.length}`);
        formDefinition.groups.forEach((group, groupIndex) => {
            keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
            group.parameters.forEach((param, paramIndex) => {
                keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
            });
        });
        if (formDefinition.mode) {
            keyParts.push(`mode:${formDefinition.mode}`);
        }
        // Join with delimiter and create a shorter hash
        const keyString = keyParts.join('|');
        // If still too long, create a simple hash
        if (keyString.length > 100) {
            return this.createSimpleHash(keyString);
        }
        return keyString;
    }
    /**
     * Create cache key for widget tree
     */
    createWidgetTreeCacheKey(widgetTree) {
        // Create a hash-like key instead of full JSON string
        const keyParts = [];
        keyParts.push(`type:${widgetTree.type}`);
        if (widgetTree.name) {
            keyParts.push(`name:${widgetTree.name}`);
        }
        if (widgetTree.children) {
            keyParts.push(`children:${widgetTree.children.length}`);
            widgetTree.children.forEach((child, index) => {
                keyParts.push(`c${index}:${child.type}`);
                if (child.children) {
                    keyParts.push(`cc${index}:${child.children.length}`);
                    child.children.forEach((grandChild, gIndex) => {
                        keyParts.push(`gc${index}.${gIndex}:${grandChild.type}`);
                        if (grandChild.children) {
                            keyParts.push(`gcc${index}.${gIndex}:${grandChild.children.length}`);
                        }
                    });
                }
            });
        }
        // Join with delimiter and create a shorter hash
        const keyString = keyParts.join('|');
        // If still too long, create a simple hash
        if (keyString.length > 100) {
            return this.createSimpleHash(keyString);
        }
        return keyString;
    }
    /**
     * Create a simple hash from a string
     */
    createSimpleHash(str) {
        let hash = 0;
        if (str.length === 0)
            return hash.toString();
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = (hash << 5) - hash + char;
            hash = hash & hash; // Convert to 32-bit integer
        }
        return Math.abs(hash).toString(36); // Convert to base36 for shorter string
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }] });

//#region ----   Inheritance Utilities   ----
/**
 * Resolves inherited properties from context and local values
 */
function resolveInheritedProperties(context, localValues = {}) {
    return {
        mode: localValues.mode ?? context.mode ?? 'edit',
        disabled: localValues.disabled ?? context.disabled,
        readonly: localValues.readonly ?? context.readonly,
        direction: localValues.direction ?? context.direction,
        visible: localValues.visible ?? context.visible,
    };
}
/**
 * Merges inheritance context with local overrides
 */
function mergeInheritanceContext(parentContext, localOverrides = {}) {
    return {
        ...parentContext,
        ...localOverrides,
    };
}
/**
 * Generates a random string for path/name generation
 */
function generateRandomId() {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}
/**
 * Converts label to a valid path/name
 */
function labelToPath(label) {
    return label
        .toLowerCase()
        .replace(/[^a-z0-9\s]/g, '') // Remove special characters
        .replace(/\s+/g, '_') // Replace spaces with underscores
        .substring(0, 50); // Limit length
}
/**
 * Generates path for value widgets based on hierarchy
 */
function generateValueWidgetPath(widgetName, formFieldName, formFieldLabel) {
    // Priority: widget name -> form field name -> generated from label -> random
    if (widgetName) {
        return widgetName;
    }
    if (formFieldName) {
        return formFieldName;
    }
    if (formFieldLabel) {
        return labelToPath(formFieldLabel);
    }
    return generateRandomId();
}
/**
 * Collects default values from widget node tree and merges them into context
 * Only sets values for paths that don't already exist in the context
 * @param node - The widget node to process
 * @param context - The context object to modify in place (cloned at top level only)
 * @param isTopLevel - Internal flag to track if this is the top-level call
 */
function collectDefaultValues(node, context = {}, isTopLevel = true) {
    // Clone context only at the top level, then modify in place for recursive calls
    const result = isTopLevel ? cloneDeep(context) : context;
    // Check if this node has a defaultValue and a path
    // Note: We check for both node.defaultValue and also look in node.options.defaultValue as fallback
    const defaultValue = node.defaultValue !== undefined ? node.defaultValue : node.options?.defaultValue;
    if (defaultValue !== undefined && !isNil(defaultValue) && node.path) {
        // Check if path exists in context using lodash get equivalent check
        const currentValue = getNestedValue(result, node.path);
        if (currentValue === undefined) {
            // Clone the defaultValue to avoid reference issues (especially for Date objects)
            const clonedValue = defaultValue instanceof Date ? new Date(defaultValue.getTime()) : cloneDeep(defaultValue);
            set(result, node.path, clonedValue);
        }
    }
    // Recursively process children - pass result object to accumulate values in place
    if (node.children && Array.isArray(node.children)) {
        for (const child of node.children) {
            collectDefaultValues(child, result, false);
        }
    }
    return result;
}
/**
 * Gets a nested value from an object using dot notation path
 */
function getNestedValue(obj, path) {
    const keys = path.split('.');
    let current = obj;
    for (const key of keys) {
        if (current === undefined || current === null || typeof current !== 'object') {
            return undefined;
        }
        current = current[key];
    }
    return current;
}
//#endregion
//#region ----   Service Implementation   ----
class AXPLayoutBuilderService {
    constructor() {
        this.popupService = inject(AXPopupService);
    }
    /**
     * Create a new layout builder
     */
    create() {
        return new LayoutBuilder(this.popupService);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutBuilderService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutBuilderService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }] });
//#endregion
//#region ----   Layout Builder Implementation   ----
/**
 * Main layout builder - Single Responsibility: Layout orchestration
 * Open/Closed: Extensible through container delegates
 */
class LayoutBuilder {
    constructor(popupService) {
        this.popupService = popupService;
        this.root = {
            children: [],
            mode: 'edit',
            type: 'flex-layout',
        };
        this.inheritanceContext = {
            mode: 'edit',
        };
    }
    // Predefined layout containers at root level - delegate pattern required
    grid(delegate) {
        const container = new GridContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        //this.state.children!.push(container.build());
        this.root = container.build();
        return this;
    }
    flex(delegate) {
        const container = new FlexContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.root.children.push(container.build());
        return this;
    }
    panel(delegate) {
        const container = new PanelContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.root.children.push(container.build());
        return this;
    }
    page(delegate) {
        const container = new PageContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.root.children.push(container.build());
        return this;
    }
    tabset(delegate) {
        const container = new TabsetContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.root.children.push(container.build());
        return this;
    }
    fieldset(delegate) {
        const container = new FieldsetContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.root.children.push(container.build());
        return this;
    }
    dialog(delegate) {
        if (!this.popupService) {
            throw new Error('LayoutBuilder requires AXPopupService to create dialogs. Please inject it in the service constructor.');
        }
        const container = new DialogContainerBuilder(this.popupService);
        if (delegate) {
            delegate(container);
        }
        return container;
    }
    stepWizard(delegate) {
        const wizard = new StepWizardBuilder();
        wizard.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(wizard);
        }
        this.root.children.push(wizard.build());
        return this;
    }
    formField(label, delegate) {
        const field = new FormFieldBuilder(label);
        field.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(field);
        }
        this.root.children.push(field.build());
        return this;
    }
    build() {
        return {
            type: this.root.type,
            children: this.root.children,
            mode: this.root.mode,
        };
    }
    /**
     * Converts the built widget node to JSON string
     * @param options - Serialization options
     * @returns JSON string representation of the widget node
     */
    toJson(options) {
        const node = this.build();
        return AXPWidgetSerializationHelper.toJson(node, options);
    }
}
//#endregion
//#region ----   Container Builder Implementation   ----
/**
 * Abstract base container builder - Open/Closed Principle
 * Provides common functionality for all container types
 */
class BaseContainerBuilder {
    constructor(containerType) {
        this.containerState = {
            mode: 'edit',
            type: 'flex-layout',
            children: [],
        };
        this.inheritanceContext = {};
        this.containerState.type = containerType;
    }
    // Base methods shared by all containers
    ensureChildren() {
        this.containerState.children = this.containerState.children || [];
    }
    addWidget(type, options) {
        const child = new WidgetBuilder();
        child.type(type);
        // For value widgets, ensure path is provided
        const widgetOptions = options ?? {};
        const path = widgetOptions.path;
        const name = widgetOptions.name;
        if (this.isValueWidget(type) && !path) {
            throw new Error(`Value widget '${type}' requires a 'path' property`);
        }
        // Set name and path in widget state, not options
        if (name) {
            child.name(name);
        }
        if (path) {
            child.path(path);
        }
        // Remove name and path from options
        const { name: _, path: __, ...cleanOptions } = widgetOptions;
        // IMPORTANT: Apply inheritance context BEFORE setting options
        // This ensures that inherited properties (readonly, disabled, etc.) are applied first
        // Then user-provided options will override them if explicitly set
        child.withInheritanceContext(this.inheritanceContext);
        child.options(cleanOptions);
        this.ensureChildren();
        this.containerState.children.push(child.build());
        return this;
    }
    isValueWidget(type) {
        const valueWidgetTypes = [
            'text-editor',
            'large-text-editor',
            'rich-text-editor',
            'password-editor',
            'number-editor',
            'select-editor',
            'lookup-editor',
            'selection-list-editor',
            'date-time-editor',
            'toggle-editor',
            'color-editor',
        ];
        return valueWidgetTypes.includes(type);
    }
    build() {
        const result = {
            type: this.containerState.type,
            children: this.containerState.children,
            options: this.containerState.options,
            mode: this.containerState.mode,
            visible: this.containerState.visible,
        };
        // Add name with _form_field suffix for form fields
        if (this.containerState.type === 'form-field') {
            if (this.containerState.name) {
                result.name = this.containerState.name;
            }
            else if (this.containerState.options?.['label']) {
                result.name = labelToPath(this.containerState.options['label']) + '_form_field';
            }
            // Form fields don't have path
        }
        else {
            // Other containers can have name and path
            if (this.containerState.name) {
                result.name = this.containerState.name;
            }
            if (this.containerState.path) {
                result.path = this.containerState.path;
            }
            if (this.containerState.defaultValue !== undefined) {
                result.defaultValue = this.containerState.defaultValue;
            }
        }
        return result;
    }
}
/**
 * Base container builder mixin - Interface Segregation Principle
 * Provides common container operations
 */
class BaseContainerMixin extends BaseContainerBuilder {
    name(name) {
        this.containerState.name = name;
        return this;
    }
    path(path) {
        this.containerState.path = path;
        return this;
    }
    mode(mode) {
        this.containerState.mode = mode;
        this.inheritanceContext.mode = mode;
        return this;
    }
    visible(condition) {
        if (!this.containerState.options)
            this.containerState.options = {};
        this.containerState.options['visible'] = condition;
        this.inheritanceContext.visible = condition;
        return this;
    }
    disabled(condition) {
        if (!this.containerState.options)
            this.containerState.options = {};
        this.containerState.options['disabled'] = condition;
        this.inheritanceContext.disabled = condition;
        return this;
    }
    readonly(condition) {
        if (!this.containerState.options)
            this.containerState.options = {};
        this.containerState.options['readonly'] = condition;
        this.inheritanceContext.readonly = condition;
        return this;
    }
    direction(direction) {
        if (!this.containerState.options)
            this.containerState.options = {};
        this.containerState.options['direction'] = direction;
        this.inheritanceContext.direction = direction;
        return this;
    }
    // Inheritance context methods
    withInheritanceContext(context) {
        this.inheritanceContext = mergeInheritanceContext(context);
        return this;
    }
    getInheritanceContext() {
        return { ...this.inheritanceContext };
    }
}
/**
 * Layout container mixin - Interface Segregation Principle
 * Provides layout-specific operations
 */
class LayoutContainerMixin extends BaseContainerMixin {
    layout(value) {
        // Map layout intent to grid item sizing so containers like `form-field`
        // can span multiple columns inside grid/fieldset layouts.
        if (!this.containerState.options)
            this.containerState.options = {};
        if (typeof value === 'number') {
            // Direct numeric shorthand → colSpan
            this.containerState.options.colSpan = value;
        }
        else if (value) {
            // Try to extract a reasonable colSpan from breakpoint positions
            const positions = value.positions;
            if (positions) {
                const colSpan = positions?.lg?.colSpan ??
                    positions?.xl?.colSpan ??
                    positions?.xxl?.colSpan ??
                    positions?.md?.colSpan ??
                    positions?.sm?.colSpan;
                if (colSpan != null) {
                    this.containerState.options.colSpan = colSpan;
                }
            }
        }
        return this;
    }
}
/**
 * Child container mixin - Interface Segregation Principle
 * Provides child container management
 */
class ChildContainerMixin extends LayoutContainerMixin {
    grid(delegate) {
        const container = new GridContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    flex(delegate) {
        const container = new FlexContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    panel(delegate) {
        const container = new PanelContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    page(delegate) {
        const container = new PageContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    tabset(delegate) {
        const container = new TabsetContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    fieldset(delegate) {
        const container = new FieldsetContainerBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    dialog(delegate) {
        const container = new DialogContainerBuilder(); // Will use inject() fallback
        if (delegate) {
            delegate(container);
        }
        return container;
    }
    stepWizard(delegate) {
        const wizard = new StepWizardBuilder();
        wizard.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(wizard);
        }
        this.ensureChildren();
        this.containerState.children.push(wizard.build());
        return this;
    }
    formField(label, delegate) {
        const field = new FormFieldBuilder(label);
        field.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(field);
        }
        this.ensureChildren();
        this.containerState.children.push(field.build());
        return this;
    }
    dynamicForm(definition) {
        // Get conversion service using inject() - works in any context in Angular 14+
        let conversionService;
        try {
            conversionService = inject(AXPLayoutConversionService);
        }
        catch {
            // Fallback: create service instance if inject() fails (shouldn't happen in normal usage)
            conversionService = new AXPLayoutConversionService();
        }
        // Convert form definition to widget node
        const widgetNode = conversionService.convertFormDefinition(definition);
        // Add the widget node's children to this container
        // The converted widget node has a root grid-layout, we want its children (fieldsets)
        if (widgetNode.children && widgetNode.children.length > 0) {
            this.ensureChildren();
            this.containerState.children.push(...widgetNode.children);
        }
        return this;
    }
}
/**
 * Widget container mixin - Interface Segregation Principle
 * Provides widget creation operations
 */
class WidgetContainerMixin extends ChildContainerMixin {
    textBox(options) {
        this.addWidget('text-editor', options);
        return this;
    }
    largeTextBox(options) {
        this.addWidget('large-text-editor', options);
        return this;
    }
    richText(options) {
        this.addWidget('rich-text-editor', options);
        return this;
    }
    passwordBox(options) {
        this.addWidget('password-editor', options);
        return this;
    }
    numberBox(options) {
        this.addWidget('number-editor', options);
        return this;
    }
    selectBox(options) {
        this.addWidget('select-editor', options);
        return this;
    }
    lookupBox(options) {
        this.addWidget('lookup-editor', options);
        return this;
    }
    selectionList(options) {
        this.addWidget('selection-list-editor', options);
        return this;
    }
    dateTimeBox(options) {
        this.addWidget('date-time-editor', options);
        return this;
    }
    toggleSwitch(options) {
        this.addWidget('toggle-editor', options);
        return this;
    }
    colorBox(options) {
        this.addWidget('color-editor', options);
        return this;
    }
    list(delegate) {
        const container = new ListWidgetBuilder();
        container.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(container);
        }
        this.ensureChildren();
        this.containerState.children.push(container.build());
        return this;
    }
    customWidget(type, optionsOrDelegate, delegate) {
        const child = new WidgetBuilder();
        child.type(type);
        // Determine if second parameter is delegate or options
        const isDelegate = typeof optionsOrDelegate === 'function';
        const options = isDelegate ? undefined : optionsOrDelegate;
        const actualDelegate = isDelegate ? optionsOrDelegate : delegate;
        // Apply inheritance context BEFORE setting options or calling delegate
        child.withInheritanceContext(this.inheritanceContext);
        // If options are provided (non-delegate overload), handle them
        if (!isDelegate && options !== undefined) {
            const widgetOptions = options;
            const path = widgetOptions.path;
            const name = widgetOptions.name;
            // Set name and path in widget state, not options
            if (name) {
                child.name(name);
            }
            if (path) {
                child.path(path);
            }
            // Remove name and path from options
            const { name: _, path: __, ...cleanOptions } = widgetOptions;
            child.options(cleanOptions);
        }
        // If delegate is provided, call it to allow setting path, options, and other control methods
        if (actualDelegate) {
            actualDelegate(child);
        }
        // Build the widget to check if path is set (for value widgets)
        const builtWidget = child.build();
        // Check if value widget requires path
        const valueWidgetTypes = [
            'text-editor',
            'large-text-editor',
            'rich-text-editor',
            'password-editor',
            'number-editor',
            'select-editor',
            'lookup-editor',
            'selection-list-editor',
            'date-time-editor',
            'toggle-editor',
            'color-editor',
        ];
        if (valueWidgetTypes.includes(type) && !builtWidget.path) {
            throw new Error(`Value widget '${type}' requires a 'path' property`);
        }
        this.ensureChildren();
        this.containerState.children.push(builtWidget);
        return this;
    }
}
/**
 * Flex Container Builder - Liskov Substitution Principle
 * Extends WidgetContainerMixin to inherit all common functionality
 */
class FlexContainerBuilder extends WidgetContainerMixin {
    constructor() {
        super('flex-layout');
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for Flex
    setDirection(direction) {
        return this.setOptions({ flexDirection: direction });
    }
    setWrap(wrap) {
        return this.setOptions({ flexWrap: wrap });
    }
    setJustifyContent(justify) {
        return this.setOptions({ justifyContent: justify });
    }
    setAlignItems(align) {
        return this.setOptions({ alignItems: align });
    }
    setGap(gap) {
        return this.setOptions({ gap });
    }
    setBackgroundColor(color) {
        return this.setOptions({ backgroundColor: color });
    }
    setPadding(padding) {
        return this.setOptions({ spacing: { padding } });
    }
    setMargin(margin) {
        return this.setOptions({ spacing: { margin } });
    }
}
/**
 * Grid Container Builder - Liskov Substitution Principle
 * Extends WidgetContainerMixin to inherit all common functionality
 */
class GridContainerBuilder extends WidgetContainerMixin {
    constructor() {
        super('grid-layout');
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for Grid
    setColumns(columns) {
        return this.setOptions({ grid: { default: { columns } } });
    }
    setRows(rows) {
        return this.setOptions({ grid: { default: { rows } } });
    }
    setGap(gap) {
        return this.setOptions({ grid: { default: { gap } } });
    }
    setJustifyItems(justify) {
        return this.setOptions({ grid: { default: { justifyItems: justify } } });
    }
    setAlignItems(align) {
        return this.setOptions({ grid: { default: { alignItems: align } } });
    }
    setAutoFlow(flow) {
        return this.setOptions({ grid: { default: { autoFlow: flow } } });
    }
    setBackgroundColor(color) {
        return this.setOptions({ backgroundColor: color });
    }
    setPadding(padding) {
        return this.setOptions({ spacing: { padding } });
    }
    setMargin(margin) {
        return this.setOptions({ spacing: { margin } });
    }
}
/**
 * Panel Container Builder - Liskov Substitution Principle
 * Extends WidgetContainerMixin to inherit all common functionality
 */
class PanelContainerBuilder extends WidgetContainerMixin {
    constructor() {
        super('panel-layout');
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for Panel
    setCaption(caption) {
        return this.setOptions({ caption });
    }
    setIcon(icon) {
        return this.setOptions({ icon });
    }
    setLook(look) {
        return this.setOptions({ look });
    }
    setShowHeader(show) {
        return this.setOptions({ showHeader: show });
    }
    setCollapsed(collapsed) {
        return this.setOptions({ collapsed });
    }
}
/**
 * Page Container Builder - Liskov Substitution Principle
 * Extends WidgetContainerMixin to inherit all common functionality
 */
class PageContainerBuilder extends WidgetContainerMixin {
    constructor() {
        super('page-layout');
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for Page
    setBackgroundColor(color) {
        return this.setOptions({ backgroundColor: color });
    }
    setTheme(theme) {
        return this.setOptions({ theme });
    }
    setHasHeader(hasHeader) {
        return this.setOptions({ hasHeader });
    }
    setHasFooter(hasFooter) {
        return this.setOptions({ hasFooter });
    }
    setDirection(direction) {
        return this.setOptions({ direction });
    }
}
/**
 * Tabset Container Builder - Liskov Substitution Principle
 * Extends WidgetContainerMixin to inherit all common functionality
 */
class TabsetContainerBuilder extends WidgetContainerMixin {
    constructor() {
        super('tabset-layout');
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for Tabset
    setLook(look) {
        return this.setOptions({ look });
    }
    setOrientation(orientation) {
        return this.setOptions({ orientation });
    }
    setActiveIndex(index) {
        return this.setOptions({ activeIndex: index });
    }
}
/**
 * Form Field Builder - Liskov Substitution Principle
 * Can only contain ONE widget with automatic path generation
 */
class FormFieldBuilder extends LayoutContainerMixin {
    constructor(label) {
        super('form-field');
        this.hasWidget = false;
        this.containerState.options = { label, showLabel: true };
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    setLabel(label) {
        return this.setOptions({ label });
    }
    setShowLabel(showLabel) {
        return this.setOptions({ showLabel });
    }
    defaultValue(value) {
        this.containerState.defaultValue = value;
        this.inheritanceContext.defaultValue = value;
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    // Single widget methods with automatic path generation
    addSingleWidget(type, options) {
        if (this.hasWidget) {
            throw new Error('Form field can only contain one widget');
        }
        const formFieldName = this.containerState.name;
        const formFieldPath = this.containerState.path; // Get explicit path from form field
        const formFieldLabel = this.containerState.options?.['label'];
        const widgetName = options?.name;
        // Generate widget path: explicit path -> widget name -> form field name -> label -> random
        let widgetPath;
        if (formFieldPath) {
            widgetPath = formFieldPath; // Use explicit form field path first
        }
        else if (widgetName) {
            widgetPath = widgetName;
        }
        else if (formFieldName) {
            widgetPath = formFieldName; // Use form field name as default path
        }
        else if (formFieldLabel) {
            widgetPath = labelToPath(formFieldLabel);
        }
        else {
            widgetPath = generateRandomId();
        }
        const finalName = widgetName || formFieldName || widgetPath;
        const child = new WidgetBuilder();
        child.type(type);
        child.name(finalName);
        child.path(widgetPath);
        // Extract extended properties from options (triggers, meta, valueTransforms, mode, visible, defaultValue)
        const { name: _, triggers, meta, valueTransforms, mode: extendedMode, visible: extendedVisible, defaultValue: extendedDefaultValue, children: extendedChildren, ...cleanOptions } = (options || {});
        child.withInheritanceContext(this.inheritanceContext);
        child.options(cleanOptions);
        // Apply extended properties if provided
        if (extendedMode !== undefined) {
            child.mode(extendedMode);
        }
        if (extendedVisible !== undefined) {
            child.visible(extendedVisible);
        }
        if (extendedDefaultValue !== undefined) {
            child.defaultValue(extendedDefaultValue);
        }
        // Set triggers, meta, and valueTransforms directly on widgetState
        // These are part of AXPWidgetNode but not handled by WidgetBuilder methods
        if (triggers !== undefined) {
            child.widgetState.triggers = triggers;
        }
        if (meta !== undefined) {
            child.widgetState.meta = meta;
        }
        if (valueTransforms !== undefined) {
            child.widgetState.valueTransforms = valueTransforms;
        }
        if (extendedChildren !== undefined) {
            child.widgetState.children = extendedChildren;
        }
        // IMPORTANT: Store the widget builder, don't build it yet!
        // This allows properties set after this method (like disabled, readonly) to be applied
        this.childWidget = child;
        this.hasWidget = true;
        return this;
    }
    textBox(options) {
        return this.addSingleWidget('text-editor', options);
    }
    largeTextBox(options) {
        return this.addSingleWidget('large-text-editor', options);
    }
    richText(options) {
        return this.addSingleWidget('rich-text-editor', options);
    }
    passwordBox(options) {
        return this.addSingleWidget('password-editor', options);
    }
    numberBox(options) {
        return this.addSingleWidget('number-editor', options);
    }
    selectBox(options) {
        return this.addSingleWidget('select-editor', options);
    }
    lookupBox(options) {
        return this.addSingleWidget('lookup-editor', options);
    }
    selectionList(options) {
        return this.addSingleWidget('selection-list-editor', options);
    }
    dateTimeBox(options) {
        return this.addSingleWidget('date-time-editor', options);
    }
    toggleSwitch(options) {
        return this.addSingleWidget('toggle-editor', options);
    }
    colorBox(options) {
        return this.addSingleWidget('color-editor', options);
    }
    customWidget(type, options) {
        return this.addSingleWidget(type, options);
    }
    // Override property setters to propagate changes to child widget
    disabled(condition) {
        super.disabled(condition);
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    readonly(condition) {
        super.readonly(condition);
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    visible(condition) {
        super.visible(condition);
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    direction(direction) {
        super.direction(direction);
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    mode(mode) {
        super.mode(mode);
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    // Override withInheritanceContext to pass it to the child widget if it exists
    withInheritanceContext(context) {
        // Call parent implementation first
        super.withInheritanceContext(context);
        // If we have a child widget, update its inheritance context too
        if (this.childWidget) {
            this.childWidget.withInheritanceContext(this.inheritanceContext);
        }
        return this;
    }
    // Override build() to build the child widget at the last moment
    build() {
        // Build the child widget and add it to children before building the form field
        if (this.childWidget) {
            this.ensureChildren();
            this.containerState.children.push(this.childWidget.build());
        }
        // Call parent build
        return super.build();
    }
}
/**
 * Fieldset Container Builder - Liskov Substitution Principle
 * Extends LayoutContainerMixin to inherit layout functionality
 * Specialized for form fields only
 */
class FieldsetContainerBuilder extends LayoutContainerMixin {
    constructor() {
        super('fieldset-layout');
        this.containerState.options = {};
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for Fieldset
    setTitle(title) {
        return this.setOptions({ title });
    }
    setDescription(description) {
        return this.setOptions({ description });
    }
    setIcon(icon) {
        return this.setOptions({ icon });
    }
    setCollapsible(collapsible) {
        return this.setOptions({ collapsible });
    }
    setIsOpen(isOpen) {
        return this.setOptions({ isOpen });
    }
    setLook(look) {
        return this.setOptions({ look });
    }
    setShowHeader(showHeader) {
        return this.setOptions({ showHeader });
    }
    setCols(cols) {
        return this.setOptions({ cols });
    }
    // Only form fields are allowed in fieldset
    formField(label, delegate) {
        const field = new FormFieldBuilder(label);
        field.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(field);
        }
        this.ensureChildren();
        this.containerState.children.push(field.build());
        return this;
    }
}
/**
 * List Widget Builder - Liskov Substitution Principle
 * Extends WidgetContainerMixin to inherit all common functionality
 */
class ListWidgetBuilder extends WidgetContainerMixin {
    constructor() {
        super('data-list');
    }
    setOptions(options) {
        this.containerState.options = { ...this.containerState.options, ...options };
        return this;
    }
    // Individual fluent methods for List Widget
    setDataSource(dataSource) {
        return this.setOptions({ dataSource });
    }
    setColumns(columns) {
        return this.setOptions({ columns });
    }
    // Event handlers
    setOnRowClick(handler) {
        return this.setOptions({ onRowClick: handler });
    }
    setOnRowDoubleClick(handler) {
        return this.setOptions({ onRowDoubleClick: handler });
    }
    setOnSelectionChange(handler) {
        return this.setOptions({ onSelectionChange: handler });
    }
    setOnRowCommand(handler) {
        return this.setOptions({ onRowCommand: handler });
    }
    // Table features
    setPaging(paging) {
        return this.setOptions({ paging });
    }
    setShowHeader(show) {
        return this.setOptions({ showHeader: show });
    }
    setShowFooter(show) {
        return this.setOptions({ showFooter: show });
    }
    setFixHeader(fix) {
        return this.setOptions({ fixHeader: fix });
    }
    setFixFooter(fix) {
        return this.setOptions({ fixFooter: fix });
    }
    setFetchDataMode(mode) {
        return this.setOptions({ fetchDataMode: mode });
    }
    setParentField(field) {
        return this.setOptions({ parentField: field });
    }
    setMinHeight(height) {
        return this.setOptions({ minHeight: height });
    }
    // Selection & Index
    setShowIndex(show) {
        return this.setOptions({ showIndex: show });
    }
    setAllowSelection(allow) {
        return this.setOptions({ allowSelection: allow });
    }
    // Commands
    setPrimaryCommands(commands) {
        return this.setOptions({ primaryCommands: commands });
    }
    setSecondaryCommands(commands) {
        return this.setOptions({ secondaryCommands: commands });
    }
    // Loading
    setLoading(loading) {
        return this.setOptions({ loading });
    }
}
/**
 * Dialog Container Builder - Specialized for dialog functionality
 * Uses composition instead of inheritance for cleaner separation
 */
class DialogContainerBuilder {
    constructor(popupService) {
        this.dialogState = {
            type: 'flex-layout', // This will be overridden when content layout exists
            children: [],
            mode: 'edit',
            dialogOptions: {
                title: '',
                size: 'md',
                closeButton: false,
            },
            actions: {
                footer: {
                    prefix: [],
                    suffix: [],
                },
            },
        };
        if (popupService) {
            this.popupService = popupService;
        }
        else {
            this.popupService = inject(AXPopupService);
        }
    }
    setOptions(options) {
        this.dialogState.dialogOptions = { ...this.dialogState.dialogOptions, ...options };
        return this;
    }
    // Individual fluent methods for Dialog
    setTitle(title) {
        return this.setOptions({ title });
    }
    setMessage(message) {
        return this.setOptions({ message });
    }
    setSize(size) {
        return this.setOptions({ size });
    }
    setCloseButton(closeButton) {
        return this.setOptions({ closeButton });
    }
    setContext(context) {
        return this.setOptions({ context });
    }
    content(delegate) {
        if (delegate) {
            // Create a flex container directly instead of through LayoutBuilder
            const flexContainer = new FlexContainerBuilder();
            flexContainer.setDirection('column');
            flexContainer.setGap('10px');
            delegate(flexContainer);
            this.contentLayout = flexContainer.build();
        }
        return this;
    }
    setActions(delegate) {
        if (delegate) {
            const actionBuilder = new ActionBuilder(this);
            delegate(actionBuilder);
        }
        return this;
    }
    addCustomAction(action) {
        // Add to actions based on position
        const position = action.position || 'suffix';
        if (position === 'prefix') {
            if (!this.dialogState.actions.footer.prefix) {
                this.dialogState.actions.footer.prefix = [];
            }
            this.dialogState.actions.footer.prefix.push(action);
        }
        else {
            if (!this.dialogState.actions.footer.suffix) {
                this.dialogState.actions.footer.suffix = [];
            }
            this.dialogState.actions.footer.suffix.push(action);
        }
        return this;
    }
    // Build method to create dialog node
    build() {
        // If we have content layout, use it directly to avoid extra wrapper
        if (this.contentLayout) {
            return {
                ...this.contentLayout,
                // Add dialog-specific properties
                options: {
                    ...this.contentLayout.options,
                    ...this.dialogState.dialogOptions,
                },
            };
        }
        // Fallback to dialog state structure if no content
        const result = {
            ...this.dialogState,
            children: [],
        };
        // Add dialog-specific properties
        if (this.dialogState.dialogOptions) {
            result.options = { ...result.options, ...this.dialogState.dialogOptions };
        }
        return result;
    }
    // Dialog-specific methods
    async show() {
        const dialogNode = this.build();
        // Import the dialog renderer component dynamically
        const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
        // Collect default values from widget tree and merge into initial context
        const initialContext = this.dialogState.dialogOptions?.context || {};
        //TODO remove using collectDefaultValues and use initialContext directly for now:
        const contextWithDefaults = collectDefaultValues(dialogNode, initialContext);
        // Create dialog configuration
        const dialogConfig = {
            title: this.dialogState.dialogOptions?.title || '',
            message: this.dialogState.dialogOptions?.message,
            context: initialContext,
            definition: dialogNode,
            actions: this.dialogState.actions,
        };
        // The Promise resolves when user clicks an action button
        return new Promise(async (resolve) => {
            this.popupService.open(AXPDialogRendererComponent, {
                title: dialogConfig.title,
                size: this.dialogState.dialogOptions?.size || 'md',
                closeButton: this.dialogState.dialogOptions?.closeButton || false,
                closeOnBackdropClick: false,
                draggable: false,
                data: {
                    config: dialogConfig,
                    callBack: (result) => {
                        // Resolve with the dialog reference when user clicks an action
                        resolve(result);
                    },
                },
            });
        });
    }
}
//#endregion
//#region ----   Widget Builder Implementation   ----
/**
 * Widget Builder - Single Responsibility Principle
 * Handles individual widget configuration and building
 */
class WidgetBuilder {
    constructor(name) {
        this.widgetState = {
            type: 'widget',
            options: {},
            children: [],
        };
        this.inheritanceContext = {};
        if (name) {
            this.widgetState.name = name;
        }
    }
    type(type) {
        this.widgetState.type = type;
        return this;
    }
    name(name) {
        this.widgetState.name = name;
        if (!this.widgetState.path) {
            this.widgetState.path = name;
        }
        return this;
    }
    path(path) {
        this.widgetState.path = path;
        return this;
    }
    options(options) {
        // Extract defaultValue from options - it's an exceptional parameter that updates context, not a widget option
        if (options && options.defaultValue !== undefined) {
            this.widgetState.defaultValue = options.defaultValue;
            // Remove defaultValue from options since it's stored on the node, not in options
            const { defaultValue: _, ...cleanOptions } = options;
            // Merge clean options instead of replacing to preserve inherited properties
            this.widgetState.options = { ...this.widgetState.options, ...cleanOptions };
        }
        else {
            // Merge options instead of replacing to preserve inherited properties
            this.widgetState.options = { ...this.widgetState.options, ...options };
        }
        return this;
    }
    layout(value) {
        if (typeof value === 'number') {
            this.widgetState.layout = {
                positions: {
                    sm: { colSpan: 12 },
                    md: { colSpan: 12 },
                    lg: { colSpan: value },
                    xl: { colSpan: value },
                    xxl: { colSpan: value },
                },
            };
        }
        else {
            this.widgetState.layout = value;
        }
        return this;
    }
    mode(mode) {
        this.widgetState.mode = mode;
        this.inheritanceContext.mode = mode;
        return this;
    }
    visible(condition) {
        if (!this.widgetState.options) {
            this.widgetState.options = {};
        }
        this.widgetState.options['visible'] = condition;
        this.widgetState.visible = condition;
        this.inheritanceContext.visible = condition;
        return this;
    }
    disabled(condition) {
        if (!this.widgetState.options) {
            this.widgetState.options = {};
        }
        this.widgetState.options['disabled'] = condition;
        this.inheritanceContext.disabled = condition;
        return this;
    }
    defaultValue(defaultValue) {
        this.widgetState.defaultValue = defaultValue;
        return this;
    }
    readonly(condition) {
        if (!this.widgetState.options) {
            this.widgetState.options = {};
        }
        this.widgetState.options['readonly'] = condition;
        this.inheritanceContext.readonly = condition;
        return this;
    }
    direction(direction) {
        if (!this.widgetState.options) {
            this.widgetState.options = {};
        }
        this.widgetState.options['direction'] = direction;
        this.inheritanceContext.direction = direction;
        return this;
    }
    children(children) {
        this.widgetState.children = children;
        return this;
    }
    // Inheritance context methods
    withInheritanceContext(context) {
        this.inheritanceContext = mergeInheritanceContext(context);
        // Apply inherited properties to widget state
        const resolved = resolveInheritedProperties(context, this.inheritanceContext);
        // Always apply inherited properties (remove the conditions that check if already set)
        // This allows properties to be updated when inheritance context changes
        if (resolved.mode) {
            this.widgetState.mode = resolved.mode;
        }
        if (!this.widgetState.options)
            this.widgetState.options = {};
        if (resolved.disabled !== undefined) {
            this.widgetState.options['disabled'] = resolved.disabled;
        }
        if (resolved.readonly !== undefined) {
            this.widgetState.options['readonly'] = resolved.readonly;
        }
        if (resolved.direction !== undefined) {
            this.widgetState.options['direction'] = resolved.direction;
        }
        if (resolved.visible !== undefined) {
            this.widgetState.options['visible'] = resolved.visible;
            this.widgetState.visible = resolved.visible;
        }
        if (context.defaultValue !== undefined) {
            this.widgetState.defaultValue = context.defaultValue;
        }
        return this;
    }
    getInheritanceContext() {
        return { ...this.inheritanceContext };
    }
    build() {
        const node = {
            name: this.widgetState.name,
            type: this.widgetState.type,
            options: this.widgetState.options,
            mode: this.widgetState.mode,
            path: this.widgetState.path,
            defaultValue: this.widgetState.defaultValue,
            children: this.widgetState.children,
        };
        // Add extended properties if they exist
        if (this.widgetState.triggers !== undefined) {
            node.triggers = this.widgetState.triggers;
        }
        if (this.widgetState.meta !== undefined) {
            node.meta = this.widgetState.meta;
        }
        if (this.widgetState.valueTransforms !== undefined) {
            node.valueTransforms = this.widgetState.valueTransforms;
        }
        if (this.widgetState.visible !== undefined) {
            node.visible = this.widgetState.visible;
        }
        return node;
    }
}
//#region ----   Action Builder Implementation   ----
class ActionBuilder {
    constructor(dialogBuilder) {
        this.dialogBuilder = dialogBuilder;
    }
    cancel(text) {
        if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
            this.dialogBuilder['dialogState'].actions.footer.suffix = [];
        }
        this.dialogBuilder['dialogState'].actions.footer.suffix.push({
            title: text || '@general:actions.cancel.title',
            color: 'default',
            command: { name: 'cancel' },
        });
        return this;
    }
    submit(text) {
        if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
            this.dialogBuilder['dialogState'].actions.footer.suffix = [];
        }
        this.dialogBuilder['dialogState'].actions.footer.suffix.push({
            title: text || '@general:actions.submit.title',
            color: 'primary',
            command: { name: 'submit', options: { validate: true } },
        });
        return this;
    }
    custom(action) {
        if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
            this.dialogBuilder['dialogState'].actions.footer.suffix = [];
        }
        this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
        return this;
    }
}
//#endregion
//#region ----   Step Wizard Builder Implementation   ----
/**
 * Step Builder - Builds individual steps for step wizard
 */
class StepBuilder {
    constructor(id, title) {
        this.id = id;
        this.title = title;
        this.skippable = false;
        this.inheritanceContext = {};
    }
    setIcon(icon) {
        this.icon = icon;
        return this;
    }
    setDescription(description) {
        this.description = description;
        return this;
    }
    setSkippable(skippable) {
        this.skippable = skippable;
        return this;
    }
    content(delegate) {
        if (delegate) {
            // Create LayoutBuilder in injection context (will be called from component)
            const layoutBuilder = new LayoutBuilder();
            // ✅ IMPORTANT: Propagate inheritance context to content
            layoutBuilder.inheritanceContext = { ...this.inheritanceContext };
            delegate(layoutBuilder);
            this.contentNode = layoutBuilder.build();
        }
        return this;
    }
    withInheritanceContext(context) {
        this.inheritanceContext = mergeInheritanceContext(context);
        return this;
    }
    build() {
        if (!this.contentNode) {
            throw new Error(`Step '${this.id}' must have content`);
        }
        return {
            id: this.id,
            title: this.title,
            icon: this.icon,
            description: this.description,
            skippable: this.skippable,
            content: this.contentNode,
        };
    }
}
/**
 * Step Wizard Builder - Builds step wizard widget
 */
class StepWizardBuilder extends LayoutContainerMixin {
    constructor() {
        super('step-wizard');
        this.steps = [];
        this.linear = true;
        this.wizardDirection = 'horizontal';
    }
    setLinear(linear) {
        this.linear = linear;
        return this;
    }
    setDirection(direction) {
        this.wizardDirection = direction;
        return this;
    }
    setLook(look) {
        this.look = look;
        return this;
    }
    setShowActions(show) {
        this.showActions = show;
        return this;
    }
    setActions(actions) {
        this.wizardActions = actions;
        return this;
    }
    setGuards(guards) {
        this.guards = guards;
        return this;
    }
    setEvents(events) {
        this.events = events;
        return this;
    }
    step(id, title, delegate) {
        const stepBuilder = new StepBuilder(id, title);
        // ✅ IMPORTANT: Propagate inheritance context to step
        stepBuilder.withInheritanceContext(this.inheritanceContext);
        if (delegate) {
            delegate(stepBuilder);
        }
        this.steps.push(stepBuilder.build());
        return this;
    }
    build() {
        // ✅ Validation
        if (this.steps.length === 0) {
            throw new Error('StepWizard must have at least one step');
        }
        // ✅ Check duplicate IDs
        const ids = this.steps.map((s) => s.id);
        const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
        if (duplicates.length > 0) {
            throw new Error(`Duplicate step IDs found: ${duplicates.join(', ')}`);
        }
        const definition = {
            steps: this.steps,
            linear: this.linear,
            direction: this.wizardDirection,
            look: this.look,
            // Do not auto-detect based on dialog context; keep explicit or undefined
            showActions: this.showActions,
            actions: this.wizardActions,
            guards: this.guards,
            events: this.events,
        };
        const node = {
            name: this.containerState.name,
            type: 'step-wizard',
            options: { definition },
            mode: this.containerState.mode,
        };
        return node;
    }
}

class AXPLayoutRendererComponent {
    constructor() {
        this.conversionService = inject(AXPLayoutConversionService);
        /**
         * RxJS subjects for context management
         */
        this.contextUpdateSubject = new Subject();
        this.contextChangeSubject = new Subject();
        //#region ----   Inputs   ----
        /**
         * Form definition containing groups and fields OR widget tree
         */
        this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : []));
        /**
         * Form context/model data
         */
        this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
        /**
         * Form appearance and density styling (normal, compact, spacious)
         */
        this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : []));
        /**
         * Default form mode. Can be overridden by section/group and field.
         */
        this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : []));
        //#endregion
        //#region ----   Widget Tree Conversion   ----
        this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : []));
        /**
         * Convert layout data to widget tree when inputs change
         */
        this.conversionEffect = effect(() => {
            const inputData = this.layout();
            // Convert to widget tree
            let tree;
            if (this.isFormDefinition(inputData)) {
                // Convert form definition to widget tree
                tree = this.conversionService.convertFormDefinition(inputData);
            }
            else if (this.isWidgetNode(inputData)) {
                // Use widget tree directly
                tree = inputData;
            }
            else {
                console.warn('AXPLayoutRendererComponent: Invalid layout input. Expected AXPDynamicFormDefinition or AXPWidgetNode.', inputData);
                return;
            }
            // Update widget tree only if changed (Angular effect already prevents unnecessary runs)
            const prev = this.widgetTree();
            if (!isEqual(prev, tree)) {
                this.widgetTree.set(tree);
            }
        }, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : []));
        //#endregion
        //#region ----   Outputs   ----
        /**
         * Emitted when context change is initiated
         */
        this.contextInitiated = output();
        /**
         * Emitted when form becomes valid/invalid
         */
        this.validityChange = output();
        //#endregion
        //#region ----   Properties   ----
        this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : []));
        this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
        /**
         * Internal context signal for reactivity
         */
        this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : []));
        /**
         * Initial context for reset functionality
         */
        this.initialContext = {};
        //#endregion
        //#region ----   Effects   ----
        /**
         * Effect to sync context changes from external to internal (optimized with RxJS)
         */
        this.#contextSyncEffect = effect(() => {
            const ctx = this.context() ?? {};
            this.contextUpdateSubject.next(ctx);
        }, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : []));
        /**
         * Effect to handle widget tree status changes
         */
        this.#widgetStatusEffect = effect(() => {
            const widgetTree = this.widgetTree();
            if (widgetTree) {
                this.container()?.builderService.setStatus(AXPPageStatus.Rendered);
            }
        }, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : []));
    }
    //#endregion
    //#region ----   Lifecycle Methods   ----
    ngOnInit() {
        // Initialize internal context with input context
        const ctx = this.context() ?? {};
        this.internalContext.set(ctx);
        // Store initial context for reset functionality
        this.initialContext = cloneDeep(ctx);
        // Setup RxJS streams for context management
        this.setupContextStreams();
    }
    //#endregion
    //#region ----   Effects   ----
    /**
     * Effect to sync context changes from external to internal (optimized with RxJS)
     */
    #contextSyncEffect;
    /**
     * Effect to handle widget tree status changes
     */
    #widgetStatusEffect;
    //#endregion
    //#region ----   Event Handlers   ----
    /**
     * Handle context change events from widget container (optimized with RxJS)
     */
    handleContextChanged(event) {
        if (event.state === 'initiated') {
            this.contextInitiated.emit(event.data);
        }
        else {
            this.contextChangeSubject.next(event.data ?? {});
        }
    }
    //#endregion
    //#region ----   Public Methods   ----
    /**
     * Get the form component instance
     */
    getForm() {
        return this.form();
    }
    /**
     * Get the widget container component instance
     */
    getContainer() {
        return this.container();
    }
    /**
     * Get current form context
     */
    getContext() {
        return this.internalContext();
    }
    /**
     * Update form context programmatically
     */
    updateContext(context) {
        this.internalContext.set(context);
    }
    /**
     * Get the current widget tree
     */
    getWidgetTree() {
        return this.widgetTree();
    }
    /**
     * Validate the form
     */
    async validate() {
        const form = this.form();
        if (form) {
            const isValid = await form.validate();
            this.validityChange.emit(isValid.result);
            return isValid;
        }
        return {
            result: false,
            messages: [],
            rules: [],
        };
    }
    /**
     * Clear the form context
     */
    clear() {
        // Clear internal context
        this.internalContext.set({});
        // Update the model signal
        this.context.set({});
    }
    /**
     * Reset the form to its initial state
     */
    reset() {
        // Reset to initial context
        const resetContext = cloneDeep(this.initialContext);
        this.internalContext.set(resetContext);
        // Update the model signal
        this.context.set(resetContext);
    }
    //#endregion
    //#region ----   RxJS Stream Setup   ----
    /**
     * Setup RxJS streams for context management
     */
    setupContextStreams() {
        // Debounced context updates from external source
        this.contextUpdateSubject
            .pipe(debounceTime(16), // ~60fps
        distinctUntilChanged((prev, curr) => isEqual(prev, curr)), startWith(this.context() ?? {}))
            .subscribe((ctx) => {
            this.internalContext.set(ctx);
        });
        // Debounced context changes from widgets
        this.contextChangeSubject
            .pipe(debounceTime(16), // ~60fps
        distinctUntilChanged((prev, curr) => isEqual(prev, curr)))
            .subscribe((ctx) => {
            this.internalContext.set(ctx);
            // Update the model signal directly - it will emit change events automatically
            this.context.set(this.internalContext());
        });
    }
    //#endregion
    //#region ----   Type Guards   ----
    /**
     * Type guard to check if the input is a form definition
     */
    isFormDefinition(data) {
        return data && typeof data === 'object' && 'groups' in data && Array.isArray(data.groups);
    }
    /**
     * Type guard to check if the input is a widget node
     */
    isWidgetNode(data) {
        return data && typeof data === 'object' && 'type' in data && typeof data.type === 'string';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPLayoutRendererComponent, isStandalone: true, selector: "axp-layout-renderer", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { context: "contextChange", contextInitiated: "contextInitiated", validityChange: "validityChange" }, viewQueries: [{ propertyName: "form", first: true, predicate: AXFormComponent, descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
    <ax-form>
      <axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
        @if (widgetTree()) {
          <ng-container axp-widget-renderer [node]="widgetTree()!" [mode]="mode()"></ng-container>
        }
      </axp-widgets-container>
    </ax-form>
  `, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i2.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
            type: Component,
            args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [CommonModule, AXPWidgetCoreModule, AXFormModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
    <ax-form>
      <axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
        @if (widgetTree()) {
          <ng-container axp-widget-renderer [node]="widgetTree()!" [mode]="mode()"></ng-container>
        }
      </axp-widgets-container>
    </ax-form>
  `, styles: [":host{display:block;width:100%}\n"] }]
        }], propDecorators: { layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }, { type: i0.Output, args: ["contextChange"] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], contextInitiated: [{ type: i0.Output, args: ["contextInitiated"] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], form: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXFormComponent), { isSignal: true }] }], container: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPWidgetContainerComponent), { isSignal: true }] }] } });

class LayoutBuilderModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LayoutBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: LayoutBuilderModule, imports: [CommonModule, AXPLayoutRendererComponent], exports: [AXPLayoutRendererComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LayoutBuilderModule, providers: [AXPLayoutBuilderService], imports: [CommonModule, AXPLayoutRendererComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LayoutBuilderModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [CommonModule, AXPLayoutRendererComponent],
                    providers: [AXPLayoutBuilderService],
                    exports: [AXPLayoutRendererComponent],
                }]
        }] });

//#endregion

class AXPDialogRendererComponent extends AXBasePageComponent {
    constructor() {
        super(...arguments);
        this.result = new EventEmitter();
        this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
        this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
        // This will be set by the popup service automatically - same as dynamic-dialog
        this.callBack = () => { };
        this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : []));
        // Aggregated actions for footer rendering
        this.footerPrefix = signal([], ...(ngDevMode ? [{ debugName: "footerPrefix" }] : []));
        this.footerSuffix = signal([], ...(ngDevMode ? [{ debugName: "footerSuffix" }] : []));
        //#endregion
        //#region ----   View Accessors   ----
        // Access the internal layout renderer to reach the widgets container injector
        this.layoutRenderer = viewChild(AXPLayoutRendererComponent, ...(ngDevMode ? [{ debugName: "layoutRenderer" }] : []));
        this.#eff = effect(() => {
            let count = 0;
            this.aggregateAndEvaluateActions();
            if (!this.widgetCoreService) {
                const renderer = this.layoutRenderer();
                const container = renderer?.getContainer();
                this.widgetCoreService = container?.builderService ?? null;
                count = this.widgetCoreService?.registeredWidgetsCount();
            }
            else {
                count = this.widgetCoreService?.registeredWidgetsCount();
                // Clear existing timer
                if (this.debounceTimer) {
                    clearTimeout(this.debounceTimer);
                }
                // Set new timer to call after 200ms of no count changes
                this.debounceTimer = setTimeout(() => {
                    this.aggregateAndEvaluateActions();
                }, 200);
            }
        }, ...(ngDevMode ? [{ debugName: "#eff" }] : []));
    }
    //#endregion
    //#region ----   Lifecycle   ----
    ngOnInit() {
        this.context.set(this.config?.context || {});
    }
    #eff;
    //#endregion
    handleContextChanged(event) {
        this.context.set(event);
        this.aggregateAndEvaluateActions();
    }
    handleContextInitiated(event) {
        this.context.set(event);
        this.aggregateAndEvaluateActions();
    }
    footerPrefixActions() {
        return this.footerPrefix();
    }
    footerSuffixActions() {
        return this.footerSuffix();
    }
    isFormLoading() {
        return this.isDialogLoading();
    }
    isSubmitting() {
        return this.isDialogLoading();
    }
    async executeAction(action) {
        const cmd = action.command;
        if (cmd !== 'cancel') {
            const isValid = await this.layoutRenderer()?.validate();
            if (!isValid?.result) {
                return;
            }
        }
        if (typeof cmd === 'string' && cmd.startsWith('widget:')) {
            const parsed = this.parseWidgetCommand(cmd);
            if (parsed.widgetName && parsed.action) {
                await this.executeWidgetApi(parsed.widgetName, parsed.action);
                await this.aggregateAndEvaluateActions();
                return;
            }
        }
        // Fallback: treat as regular dialog action (cancel/confirm/custom)
        const result = { context: this.context(), action: cmd };
        this.dialogResult = result;
        if (this.data) {
            this.data.context = result.context;
            this.data.action = result.action;
        }
        this.callBack({
            close: (result) => {
                this.close(result);
            },
            context: () => this.context(),
            action: () => result.action,
            setLoading: (loading) => {
                this.isDialogLoading.set(loading);
            },
        });
    }
    parseWidgetCommand(cmd) {
        // Expected 'widget:<widgetName>.<action>'
        if (!cmd?.startsWith('widget:'))
            return {};
        const rest = cmd.slice('widget:'.length);
        const dot = rest.lastIndexOf('.');
        if (dot <= 0)
            return {};
        return { widgetName: rest.slice(0, dot), action: rest.slice(dot + 1) };
    }
    async executeWidgetApi(widgetName, apiMethod) {
        if (!this.widgetCoreService)
            return;
        try {
            const widget = this.widgetCoreService.getWidget(widgetName);
            const api = widget?.api?.();
            const fn = api?.[apiMethod];
            if (typeof fn === 'function') {
                await Promise.resolve(fn({
                    close: (result) => {
                        this.close(result);
                    },
                    context: () => this.context(),
                    setLoading: (loading) => {
                        this.isDialogLoading.set(loading);
                    },
                }));
            }
        }
        catch { }
    }
    async close(result) {
        if (result) {
            const isValid = await this.layoutRenderer()?.validate();
            if (isValid?.result) {
                this.result.emit(result);
            }
        }
        super.close(result);
    }
    // --- Actions aggregation & evaluation ---
    async aggregateAndEvaluateActions() {
        const widgetActions = await this.collectWidgetActions();
        const dialogActions = this.collectDialogActionsFromConfig();
        const all = [...widgetActions, ...dialogActions];
        const evaluated = await this.evaluatePredicates(all);
        const visible = evaluated.filter((a) => a.hidden !== true);
        const prefix = visible.filter((a) => (a.zone ?? 'footer') === 'footer' && (a.placement ?? 'suffix') === 'prefix');
        const suffix = visible.filter((a) => (a.zone ?? 'footer') === 'footer' && (a.placement ?? 'suffix') === 'suffix');
        this.footerPrefix.set(prefix);
        this.footerSuffix.set(suffix);
    }
    async collectWidgetActions() {
        if (!this.widgetCoreService)
            return [];
        const names = this.widgetCoreService.listRegisteredWidgetNames();
        const actions = [];
        for (const name of names) {
            try {
                const widget = this.widgetCoreService.getWidget(name);
                const widgetActs = widget?.actions?.() ?? [];
                actions.push(...widgetActs);
            }
            catch { }
        }
        return actions;
    }
    collectDialogActionsFromConfig() {
        const footer = this.config?.actions?.footer;
        const mapOne = (a, placement) => ({
            title: a.title,
            command: typeof a.command === 'string' ? a.command : a.command?.name,
            icon: a.icon,
            color: a.color,
            disabled: a.disabled,
            hidden: a.hidden,
            zone: 'footer',
            placement,
            scope: a.scope,
        });
        const prefix = (footer?.prefix || []).map((a) => mapOne(a, 'prefix'));
        const suffix = (footer?.suffix || []).map((a) => mapOne(a, 'suffix'));
        return [...prefix, ...suffix];
    }
    async evaluatePredicates(actions) {
        const out = [];
        for (const a of actions) {
            const parsed = typeof a.command === 'string' ? this.parseWidgetCommand(a.command) : {};
            const api = parsed.widgetName ? await this.resolveApi(parsed.widgetName) : undefined;
            const scope = {
                api,
                widget: { name: parsed.widgetName },
                dialog: { context: this.context() },
                context: this.context(),
            };
            const disabled = await this.evalBool(a.disabled, scope);
            const hidden = await this.evalBool(a.hidden, scope);
            out.push({ ...a, disabled, hidden });
        }
        return out;
    }
    async evalBool(value, scope) {
        if (typeof value === 'boolean')
            return value;
        if (typeof value === 'string') {
            try {
                const result = await this.expressionEvaluator.evaluate(value, scope);
                return !!result;
            }
            catch {
                return false;
            }
        }
        return value;
    }
    async resolveApi(widgetName) {
        try {
            await this.widgetCoreService?.waitForWidget(widgetName, 2000);
            const widget = this.widgetCoreService?.getWidget(widgetName);
            return widget?.api?.();
        }
        catch {
            return undefined;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPDialogRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", outputs: { result: "result" }, viewQueries: [{ propertyName: "layoutRenderer", first: true, predicate: AXPLayoutRendererComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
    <div class="ax-p-4">
      <axp-layout-renderer
        [layout]="config.definition"
        [context]="context()"
        (contextChange)="handleContextChanged($event)"
        (contextInitiated)="handleContextInitiated($event)"
      >
      </axp-layout-renderer>
    </div>

    <ax-footer>
      <ax-prefix>
        @for (action of footerPrefixActions(); track $index) {
          <ax-button
            [disabled]="action.disabled || isFormLoading()"
            [text]="(action.title | translate | async)!"
            [look]="'outline'"
            [color]="action.color"
            (onClick)="executeAction(action)"
          >
            <ax-prefix>
              <i class="{{ action.icon }}"></i>
            </ax-prefix>
          </ax-button>
        }
      </ax-prefix>
      <ax-suffix>
        @for (action of footerSuffixActions(); track $index) {
          <ax-button
            [disabled]="action.disabled || isSubmitting()"
            [text]="(action.title | translate | async)!"
            [look]="'solid'"
            [color]="action.color"
            (onClick)="executeAction(action)"
          >
            @if (isFormLoading()) {
              <ax-loading></ax-loading>
            }
            @if (action.icon) {
              <ax-prefix>
                <ax-icon icon="{{ action.icon }}"></ax-icon>
              </ax-prefix>
            }
          </ax-button>
        }
      </ax-suffix>
    </ax-footer>
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i3.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPDialogRendererComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'axp-dialog-renderer',
                    standalone: true,
                    imports: [
                        CommonModule,
                        AXPLayoutRendererComponent,
                        AXButtonModule,
                        AXDecoratorModule,
                        AXLoadingModule,
                        AXTranslationModule,
                    ],
                    template: `
    <div class="ax-p-4">
      <axp-layout-renderer
        [layout]="config.definition"
        [context]="context()"
        (contextChange)="handleContextChanged($event)"
        (contextInitiated)="handleContextInitiated($event)"
      >
      </axp-layout-renderer>
    </div>

    <ax-footer>
      <ax-prefix>
        @for (action of footerPrefixActions(); track $index) {
          <ax-button
            [disabled]="action.disabled || isFormLoading()"
            [text]="(action.title | translate | async)!"
            [look]="'outline'"
            [color]="action.color"
            (onClick)="executeAction(action)"
          >
            <ax-prefix>
              <i class="{{ action.icon }}"></i>
            </ax-prefix>
          </ax-button>
        }
      </ax-prefix>
      <ax-suffix>
        @for (action of footerSuffixActions(); track $index) {
          <ax-button
            [disabled]="action.disabled || isSubmitting()"
            [text]="(action.title | translate | async)!"
            [look]="'solid'"
            [color]="action.color"
            (onClick)="executeAction(action)"
          >
            @if (isFormLoading()) {
              <ax-loading></ax-loading>
            }
            @if (action.icon) {
              <ax-prefix>
                <ax-icon icon="{{ action.icon }}"></ax-icon>
              </ax-prefix>
            }
          </ax-button>
        }
      </ax-suffix>
    </ax-footer>
  `,
                }]
        }], propDecorators: { result: [{
                type: Output
            }], layoutRenderer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPLayoutRendererComponent), { isSignal: true }] }] } });

var dialogRenderer_component = /*#__PURE__*/Object.freeze({
    __proto__: null,
    AXPDialogRendererComponent: AXPDialogRendererComponent
});

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

export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, LayoutBuilderModule };
//# sourceMappingURL=acorex-platform-layout-builder.mjs.map
