import { __decorate, __metadata } from "tslib";
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, Inject, Optional } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { LOGGER, PERMANENT_STORAGE, FirstUppercaseLocalizeSAPipe } from '@anglr/common';
import { FormModelBuilder } from '@anglr/common/forms';
import { addSimpleChange, MetadataHistoryManager } from '@anglr/dynamic';
import { DebounceCall, extend, isPresent, WithSync } from '@jscrpt/common';
import { Subscription } from 'rxjs';
import { LayoutEditorMetadataExtractor, LayoutEditorMetadataManager, LayoutEditorPropertyMetadataExtractor } from '../../services';
import { PropertiesControlsModule } from '../../modules';
import { LAYOUT_HISTORY_MANAGER } from '../../misc/tokens';
import { WidthResizerSADirective } from '../../directives';
import * as i0 from "@angular/core";
import * as i1 from "../../services";
import * as i2 from "@anglr/common/forms";
import * as i3 from "@angular/common";
import * as i4 from "@angular/forms";
import * as i5 from "../../modules/propertiesControls/directives/propertiesControlRenderer/propertiesControlRenderer.directive";
import * as i6 from "@anglr/dynamic";
const PROPERTIES_EDITOR_STATE = 'PROPERTIES_EDITOR_STATE';
/**
 * Component that represents editor for components options/properties
 */
export class PropertiesEditorSAComponent {
    //######################### constructor #########################
    constructor(manager, metadataExtractor, propertyExtractor, formModelBuilder, changeDetector, storage, history, logger) {
        this.manager = manager;
        this.metadataExtractor = metadataExtractor;
        this.propertyExtractor = propertyExtractor;
        this.formModelBuilder = formModelBuilder;
        this.changeDetector = changeDetector;
        this.storage = storage;
        this.history = history;
        this.logger = logger;
        //######################### protected properties #########################
        /**
         * Subscriptions created during initialization
         */
        this.initSubscriptions = new Subscription();
        /**
         * Subscription for options form
         */
        this.optionsFormSubscription = null;
        /**
         * Id of last component that was used for property editation
         */
        this.lastComponentId = null;
        /**
         * Instance of last component that was used for property editation
         */
        this.lastComponent = null;
        //######################### protected properties - template bindings #########################
        /**
         * Instance of selected designer component
         */
        this.component = null;
        /**
         * Instance of metadata for selected designed component
         */
        this.metadata = null;
        /**
         * Control for display name of component
         */
        this.displayName = new FormControl(null);
        /**
         * Properties data for editation
         */
        this.propertiesData = [];
        /**
         * Instance of properties editor state
         */
        this.state = { opened: false, width: 350 };
    }
    //######################### public methods - implementation of OnInit #########################
    /**
     * Initialize component
     */
    async ngOnInit() {
        const state = this.storage.get(PROPERTIES_EDITOR_STATE);
        if (state) {
            this.state = state;
        }
        this.initSubscriptions.add(this.manager.layoutChange.subscribe(() => this.initProperties()));
        this.initSubscriptions.add(this.manager.selectedChange.subscribe(() => this.initProperties()));
        this.displayName
            .valueChanges
            .subscribe(async (displayName) => {
            if (this.component?.options?.typeMetadata && isPresent(displayName)) {
                this.component.options.typeMetadata.displayName = displayName;
                const changes = {};
                addSimpleChange(changes, 'options', this.component.options, this.component.options);
                // eslint-disable-next-line no-self-assign
                this.component.options = this.component.options;
                await this.component.ngOnChanges?.(changes);
                this.manager.displayNameUpdated();
                this.history.getNewState();
            }
        });
        await this.initProperties();
    }
    //######################### public methods - implementation of OnDestroy #########################
    /**
     * Called when component is destroyed
     */
    ngOnDestroy() {
        this.initSubscriptions.unsubscribe();
        this.optionsFormSubscription?.unsubscribe();
        this.optionsFormSubscription = null;
    }
    //######################### protected methods - template bindings #########################
    /**
     * Toggles collapsed state of properties
     */
    toggleCollapsed() {
        this.state.opened = !this.state.opened;
        this.storage.set(PROPERTIES_EDITOR_STATE, this.state);
    }
    updateSize(size) {
        this.state.width -= size;
        this.storage.set(PROPERTIES_EDITOR_STATE, this.state);
        this.changeDetector.detectChanges();
    }
    //######################### protected methods #########################
    /**
     * Initialize properties for selected component
     */
    async initProperties() {
        if (isPresent(this.manager.selectedComponent)) {
            const component = this.manager.getComponent(this.manager.selectedComponent);
            if (this.lastComponent == component && this.lastComponentId == this.manager.selectedComponent) {
                return;
            }
            this.lastComponent = component;
            this.lastComponentId = this.manager.selectedComponent;
            if (component) {
                this.component = component;
                await this.getMetadata();
            }
            else {
                this.hide();
            }
        }
        else {
            this.hide();
        }
    }
    /**
     * Gets metadta for selected component
     */
    async getMetadata() {
        this.optionsFormSubscription?.unsubscribe();
        this.optionsFormSubscription = new Subscription();
        this.propertiesData = [];
        if (this.component?.options?.typeMetadata) {
            this.displayName.setValue(this.component.options.typeMetadata.displayName || this.component.options.typeMetadata.id, { emitEvent: false });
            this.metadata = await this.metadataExtractor.extractMetadata(this.component.options?.typeMetadata);
            if (!this.metadata) {
                this.logger?.error('PropertiesEditorSAComponent: unable to get metadata {{@source}}', { source: { package: this.component.options?.typeMetadata.package, name: this.component.options?.typeMetadata.name } });
                this.hide();
            }
            //properties metadata
            if (this.metadata?.metaInfo?.optionsMetadata?.propertiesMetadata?.length) {
                for (const props of this.metadata?.metaInfo?.optionsMetadata?.propertiesMetadata) {
                    this.initDynamicProperty(props);
                }
            }
            if (this.component) {
                const parent = this.manager.getParent(this.component.id);
                //gets parent metadata
                if (parent?.options?.typeMetadata) {
                    const parentMetadata = await this.metadataExtractor.extractMetadata(parent.options?.typeMetadata);
                    //parent extensions properties metadata
                    if (parentMetadata?.metaInfo?.optionsMetadata?.childPropertiesMetadata?.length) {
                        for (const props of parentMetadata?.metaInfo?.optionsMetadata?.childPropertiesMetadata) {
                            this.initDynamicProperty(props);
                        }
                    }
                }
            }
        }
        else {
            this.hide();
        }
        this.changeDetector.detectChanges();
    }
    /**
     * Hides properties
     */
    hide() {
        this.lastComponent = null;
        this.lastComponentId = null;
        this.component = null;
        this.metadata = null;
        this.propertiesData = [];
        this.optionsFormSubscription?.unsubscribe();
        this.optionsFormSubscription = null;
        this.changeDetector.detectChanges();
    }
    /**
     * Initialize dynamic property
     * @param props - Property to be initialized
     */
    initDynamicProperty(props) {
        const form = this.formModelBuilder.build(new props.modelType(this.component?.options?.typeMetadata.options));
        const metadata = this.propertyExtractor.extract(props.modelType);
        if (this.optionsFormSubscription) {
            this.optionsFormSubscription.add(form.valueChanges.subscribe(async (data) => {
                if (this.component?.options?.typeMetadata) {
                    extend(this.component.options.typeMetadata.options, data);
                    const changes = {};
                    addSimpleChange(changes, 'options', this.component.options, this.component.options);
                    // eslint-disable-next-line no-self-assign
                    this.component.options = this.component.options;
                    await this.component.ngOnChanges?.(changes);
                    this.component.invalidateVisuals();
                    this.history.getNewState();
                }
            }));
            this.propertiesData.push({
                form,
                metadata,
                controls: props.propertiesControls,
            });
        }
    }
}
PropertiesEditorSAComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: PropertiesEditorSAComponent, deps: [{ token: i1.LayoutEditorMetadataManager }, { token: i1.LayoutEditorMetadataExtractor }, { token: i1.LayoutEditorPropertyMetadataExtractor }, { token: i2.FormModelBuilder }, { token: i0.ChangeDetectorRef }, { token: PERMANENT_STORAGE }, { token: LAYOUT_HISTORY_MANAGER }, { token: LOGGER, optional: true }], target: i0.ɵɵFactoryTarget.Component });
PropertiesEditorSAComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.4", type: PropertiesEditorSAComponent, isStandalone: true, selector: "properties-editor", providers: [FormModelBuilder], ngImport: i0, template: "<div *ngIf=\"!state.opened\" class=\"properties-toolbar\">\n    <button type=\"button\" class=\"dynamic-btn-icon props-buttons\" (click)=\"toggleCollapsed()\">\n        <span class=\"dynamic-text-vertical\">{{'properties'|firstUppercaseLocalize}}</span>\n    </button>\n</div>\n\n<ng-container *ngIf=\"state.opened\">\n    <div class=\"properties-main\" [style.width.px]=\"state.width\">\n        <div class=\"header\">\n            <div class=\"header-title\">{{'properties'|firstUppercaseLocalize}}</div>\n\n            <button type=\"button\" class=\"dynamic-btn-icon\" (click)=\"toggleCollapsed()\">\n                <span class=\"fas fa-times\"></span>\n            </button>\n        </div>\n\n        <ng-container *ngIf=\"component\">\n            <div class=\"static-properties\">\n                <div class=\"properties-form-group\">\n                    <label class=\"properties-control-label\">{{'type'|firstUppercaseLocalize}}</label>\n                    <div class=\"properties-form-static\">{{metadata?.metaInfo?.name ?? component.options?.typeMetadata?.name}}</div>\n\n                    <label class=\"properties-control-label\">{{'id'|firstUppercaseLocalize}}</label>\n                    <div class=\"properties-form-static\">{{component.options?.typeMetadata?.id}}</div>\n\n                    <label class=\"properties-control-label\">{{'display name'|firstUppercaseLocalize}}</label>\n                    <input class=\"properties-form-control\" type=\"text\" [formControl]=\"displayName\">\n                </div>\n            </div>\n\n\n            <div class=\"dynamic-thin-scrollbar properties-controls\">\n                <ng-container *ngFor=\"let props of propertiesData\">\n                    <ng-container *ngFor=\"let propertiesCtrl of props.controls\">\n                        <ng-container [propertiesControl]=\"propertiesCtrl\" [form]=\"props.form\" [propertiesMetadata]=\"props.metadata\"></ng-container>\n                    </ng-container>\n                </ng-container>\n            </div>\n        </ng-container>\n    </div>\n\n    <div class=\"properties-resizer\" widthResizer (size)=\"updateSize($event)\"></div>\n</ng-container>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PropertiesControlsModule }, { kind: "directive", type: i5.PropertiesControlRendererDirective, selector: "[propertiesControl]", inputs: ["form", "propertiesMetadata", "propertiesControl"] }, { kind: "directive", type: WidthResizerSADirective, selector: "[widthResizer]", outputs: ["size"] }, { kind: "pipe", type: FirstUppercaseLocalizeSAPipe, name: "firstUppercaseLocalize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
__decorate([
    DebounceCall(10),
    WithSync(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], PropertiesEditorSAComponent.prototype, "initProperties", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: PropertiesEditorSAComponent, decorators: [{
            type: Component,
            args: [{ selector: 'properties-editor', providers: [FormModelBuilder], standalone: true, imports: [
                        CommonModule,
                        ReactiveFormsModule,
                        PropertiesControlsModule,
                        WidthResizerSADirective,
                        FirstUppercaseLocalizeSAPipe,
                    ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div *ngIf=\"!state.opened\" class=\"properties-toolbar\">\n    <button type=\"button\" class=\"dynamic-btn-icon props-buttons\" (click)=\"toggleCollapsed()\">\n        <span class=\"dynamic-text-vertical\">{{'properties'|firstUppercaseLocalize}}</span>\n    </button>\n</div>\n\n<ng-container *ngIf=\"state.opened\">\n    <div class=\"properties-main\" [style.width.px]=\"state.width\">\n        <div class=\"header\">\n            <div class=\"header-title\">{{'properties'|firstUppercaseLocalize}}</div>\n\n            <button type=\"button\" class=\"dynamic-btn-icon\" (click)=\"toggleCollapsed()\">\n                <span class=\"fas fa-times\"></span>\n            </button>\n        </div>\n\n        <ng-container *ngIf=\"component\">\n            <div class=\"static-properties\">\n                <div class=\"properties-form-group\">\n                    <label class=\"properties-control-label\">{{'type'|firstUppercaseLocalize}}</label>\n                    <div class=\"properties-form-static\">{{metadata?.metaInfo?.name ?? component.options?.typeMetadata?.name}}</div>\n\n                    <label class=\"properties-control-label\">{{'id'|firstUppercaseLocalize}}</label>\n                    <div class=\"properties-form-static\">{{component.options?.typeMetadata?.id}}</div>\n\n                    <label class=\"properties-control-label\">{{'display name'|firstUppercaseLocalize}}</label>\n                    <input class=\"properties-form-control\" type=\"text\" [formControl]=\"displayName\">\n                </div>\n            </div>\n\n\n            <div class=\"dynamic-thin-scrollbar properties-controls\">\n                <ng-container *ngFor=\"let props of propertiesData\">\n                    <ng-container *ngFor=\"let propertiesCtrl of props.controls\">\n                        <ng-container [propertiesControl]=\"propertiesCtrl\" [form]=\"props.form\" [propertiesMetadata]=\"props.metadata\"></ng-container>\n                    </ng-container>\n                </ng-container>\n            </div>\n        </ng-container>\n    </div>\n\n    <div class=\"properties-resizer\" widthResizer (size)=\"updateSize($event)\"></div>\n</ng-container>" }]
        }], ctorParameters: () => [{ type: i1.LayoutEditorMetadataManager }, { type: i1.LayoutEditorMetadataExtractor }, { type: i1.LayoutEditorPropertyMetadataExtractor }, { type: i2.FormModelBuilder }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [PERMANENT_STORAGE]
                }] }, { type: i6.MetadataHistoryManager, decorators: [{
                    type: Inject,
                    args: [LAYOUT_HISTORY_MANAGER]
                }] }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [LOGGER]
                }, {
                    type: Optional
                }] }], propDecorators: { initProperties: [] } });
//# sourceMappingURL=propertiesEditor.component.js.map