import { __awaiter, __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
     */
    ngOnInit() {
        return __awaiter(this, void 0, void 0, function* () {
            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((displayName) => __awaiter(this, void 0, void 0, function* () {
                var _a, _b, _c, _d;
                if (((_b = (_a = this.component) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.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;
                    yield ((_d = (_c = this.component).ngOnChanges) === null || _d === void 0 ? void 0 : _d.call(_c, changes));
                    this.manager.displayNameUpdated();
                    this.history.getNewState();
                }
            }));
            yield this.initProperties();
        });
    }
    //######################### public methods - implementation of OnDestroy #########################
    /**
     * Called when component is destroyed
     */
    ngOnDestroy() {
        var _a;
        this.initSubscriptions.unsubscribe();
        (_a = this.optionsFormSubscription) === null || _a === void 0 ? void 0 : _a.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
     */
    initProperties() {
        return __awaiter(this, void 0, void 0, function* () {
            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;
                    yield this.getMetadata();
                }
                else {
                    this.hide();
                }
            }
            else {
                this.hide();
            }
        });
    }
    /**
     * Gets metadta for selected component
     */
    getMetadata() {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
        return __awaiter(this, void 0, void 0, function* () {
            (_a = this.optionsFormSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
            this.optionsFormSubscription = new Subscription();
            this.propertiesData = [];
            if ((_c = (_b = this.component) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.typeMetadata) {
                this.displayName.setValue(this.component.options.typeMetadata.displayName || this.component.options.typeMetadata.id, { emitEvent: false });
                this.metadata = yield this.metadataExtractor.extractMetadata((_d = this.component.options) === null || _d === void 0 ? void 0 : _d.typeMetadata);
                if (!this.metadata) {
                    (_e = this.logger) === null || _e === void 0 ? void 0 : _e.error('PropertiesEditorSAComponent: unable to get metadata {{@source}}', { source: { package: (_f = this.component.options) === null || _f === void 0 ? void 0 : _f.typeMetadata.package, name: (_g = this.component.options) === null || _g === void 0 ? void 0 : _g.typeMetadata.name } });
                    this.hide();
                }
                //properties metadata
                if ((_l = (_k = (_j = (_h = this.metadata) === null || _h === void 0 ? void 0 : _h.metaInfo) === null || _j === void 0 ? void 0 : _j.optionsMetadata) === null || _k === void 0 ? void 0 : _k.propertiesMetadata) === null || _l === void 0 ? void 0 : _l.length) {
                    for (const props of (_p = (_o = (_m = this.metadata) === null || _m === void 0 ? void 0 : _m.metaInfo) === null || _o === void 0 ? void 0 : _o.optionsMetadata) === null || _p === void 0 ? void 0 : _p.propertiesMetadata) {
                        this.initDynamicProperty(props);
                    }
                }
                if (this.component) {
                    const parent = this.manager.getParent(this.component.id);
                    //gets parent metadata
                    if ((_q = parent === null || parent === void 0 ? void 0 : parent.options) === null || _q === void 0 ? void 0 : _q.typeMetadata) {
                        const parentMetadata = yield this.metadataExtractor.extractMetadata((_r = parent.options) === null || _r === void 0 ? void 0 : _r.typeMetadata);
                        //parent extensions properties metadata
                        if ((_u = (_t = (_s = parentMetadata === null || parentMetadata === void 0 ? void 0 : parentMetadata.metaInfo) === null || _s === void 0 ? void 0 : _s.optionsMetadata) === null || _t === void 0 ? void 0 : _t.childPropertiesMetadata) === null || _u === void 0 ? void 0 : _u.length) {
                            for (const props of (_w = (_v = parentMetadata === null || parentMetadata === void 0 ? void 0 : parentMetadata.metaInfo) === null || _v === void 0 ? void 0 : _v.optionsMetadata) === null || _w === void 0 ? void 0 : _w.childPropertiesMetadata) {
                                this.initDynamicProperty(props);
                            }
                        }
                    }
                }
            }
            else {
                this.hide();
            }
            this.changeDetector.detectChanges();
        });
    }
    /**
     * Hides properties
     */
    hide() {
        var _a;
        this.lastComponent = null;
        this.lastComponentId = null;
        this.component = null;
        this.metadata = null;
        this.propertiesData = [];
        (_a = this.optionsFormSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
        this.optionsFormSubscription = null;
        this.changeDetector.detectChanges();
    }
    /**
     * Initialize dynamic property
     * @param props - Property to be initialized
     */
    initDynamicProperty(props) {
        var _a, _b;
        const form = this.formModelBuilder.build(new props.modelType((_b = (_a = this.component) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.typeMetadata.options));
        const metadata = this.propertyExtractor.extract(props.modelType);
        if (this.optionsFormSubscription) {
            this.optionsFormSubscription.add(form.valueChanges.subscribe((data) => __awaiter(this, void 0, void 0, function* () {
                var _c, _d, _e, _f;
                if ((_d = (_c = this.component) === null || _c === void 0 ? void 0 : _c.options) === null || _d === void 0 ? void 0 : _d.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;
                    yield ((_f = (_e = this.component).ngOnChanges) === null || _f === void 0 ? void 0 : _f.call(_e, 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