import { __asyncValues, __awaiter } from "tslib";
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef, SkipSelf, Optional, Inject, Injector, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LOGGER, PositionToSADirective } from '@anglr/common';
import { LayoutComponentBase, LayoutComponentRendererSADirective } from '@anglr/dynamic/layout';
import { MetadataHistoryManager, SCOPE_ID } from '@anglr/dynamic';
import { extend, isPresent } from '@jscrpt/common';
import { DndModule } from '@ng-dnd/core';
import { Subscription } from 'rxjs';
import { isEqual } from 'lodash-es';
import { BodyRenderSADirective, CopyDesignerStylesSADirective, DesignerDropzoneSADirective, DesignerMinDimensionSADirective } from '../../directives';
import { LayoutComponentsIteratorService, LayoutEditorMetadataExtractor, LayoutEditorMetadataManager } from '../../services';
import { LayoutEditorDragPreviewSAComponent } from '../layoutEditorDragPreview/layoutEditorDragPreview.component';
import { LayoutDesignerOverlayForSAComponent } from '../layoutDesignerOverlayFor/layoutDesignerOverlayFor.component';
import { LAYOUT_HISTORY_MANAGER } from '../../misc/tokens';
import { DndCoreDesignerDirective, LayoutDndCoreModule } from '../../modules';
import * as i0 from "@angular/core";
import * as i1 from "../../services";
import * as i2 from "@angular/common";
import * as i3 from "@ng-dnd/core";
import * as i4 from "../../modules/layoutDndCore/directives/dndCoreDesigner/dndCoreDesigner.directive";
import * as i5 from "@anglr/dynamic";
/**
 * Component used as designer component wrapper for layout component
 */
export class LayoutDesignerSAComponent extends LayoutComponentBase {
    //######################### protected properties - template bindings #########################
    /**
     * Indication whether is component selected
     */
    get selected() {
        var _a;
        return this.layoutEditorMetadataManager.selectedComponent === ((_a = this.options) === null || _a === void 0 ? void 0 : _a.typeMetadata.id);
    }
    /**
     * Indication whether is component highlighted
     */
    get highlighted() {
        var _a;
        return this.layoutEditorMetadataManager.highlightedComponent === ((_a = this.options) === null || _a === void 0 ? void 0 : _a.typeMetadata.id);
    }
    //######################### protected properties - overrides #########################
    /**
     * @inheritdoc
     */
    get element() {
        return this.designerElement;
    }
    /**
     * @inheritdoc
     */
    get extensionsOptions() {
        var _a;
        return (_a = this.options) === null || _a === void 0 ? void 0 : _a.typeMetadata.options;
    }
    //######################### public properties #########################
    /**
     * Indication whether drag is disabled for component
     */
    get dragDisabled() {
        var _a, _b;
        return !this.parent || !!((_b = (_a = this.editorMetadata) === null || _a === void 0 ? void 0 : _a.metaInfo) === null || _b === void 0 ? void 0 : _b.dragDisabled);
    }
    /**
     * Component identifier
     */
    get id() {
        var _a, _b, _c;
        return (_c = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.typeMetadata) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : '';
    }
    //######################### constructor #########################
    constructor(changeDetector, element, injector, metadataExtractor, layoutEditorMetadataManager, iteratorSvc, history, scopeId, logger, parent) {
        super(changeDetector, element, injector, logger);
        this.metadataExtractor = metadataExtractor;
        this.layoutEditorMetadataManager = layoutEditorMetadataManager;
        this.iteratorSvc = iteratorSvc;
        this.history = history;
        this.scopeId = scopeId;
        this.parent = parent;
        //######################### protected properties #########################
        /**
         * Subscriptions created during initialization
         */
        this.initSubscriptions = new Subscription();
        /**
         * Indication whether item can be dropped here
         */
        this.canDrop = false;
        /**
         * Indication whether drop list is horizontally oriented
         */
        this.horizontal = false;
        /**
         * Index of current layout designer in its parent
         */
        this.index = 0;
        /**
         * Layout editor metadata
         */
        this.editorMetadata = null;
    }
    //######################### public methods - implementation of OnDestroy #########################
    /**
     * Called when component is destroyed
     */
    ngOnDestroy() {
        var _a, _b;
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('LayoutDesignerSAComponent: Destroying component {{@data}}', { data: { id: (_b = this.options) === null || _b === void 0 ? void 0 : _b.typeMetadata.id } });
        this.initSubscriptions.unsubscribe();
        super.ngOnDestroy();
        if (this.options) {
            this.layoutEditorMetadataManager.unregisterLayoutDesignerComponent(this.options.typeMetadata.id);
        }
    }
    //######################### public methods #########################
    /**
     * Adds descentant component metadata to this component metadata
     * @param dragData - Data from drag n drop event
     */
    addDescendant(dragData) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        if (!this.options) {
            return;
        }
        const parentId = dragData.parentId;
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('LayoutDesignerSAComponent: Adding descendant {{@data}}', { data: { id: (_b = dragData.metadata) === null || _b === void 0 ? void 0 : _b.id, parent: this.options.typeMetadata.id } });
        if (!dragData.metadata) {
            (_c = this.logger) === null || _c === void 0 ? void 0 : _c.warn('LayoutDesignerSAComponent: Missing metadata while adding descendant');
            return;
        }
        //already added to tree, removing old reference
        if (parentId) {
            this.history.disable();
            (_d = this.layoutEditorMetadataManager.getComponent(parentId)) === null || _d === void 0 ? void 0 : _d.removeDescendant((_e = dragData.metadata) === null || _e === void 0 ? void 0 : _e.id);
            this.history.enable();
        }
        (_g = (_f = this.editorMetadata) === null || _f === void 0 ? void 0 : _f.addDescendant) === null || _g === void 0 ? void 0 : _g.call(_f, dragData === null || dragData === void 0 ? void 0 : dragData.metadata, this.options.typeMetadata.options, (_h = dragData.index) !== null && _h !== void 0 ? _h : 0);
        this.canDrop = (_l = (_k = (_j = this.editorMetadata) === null || _j === void 0 ? void 0 : _j.canDropMetadata) === null || _k === void 0 ? void 0 : _k.call(_j, this.options.typeMetadata.options)) !== null && _l !== void 0 ? _l : false;
        this.renderedType = Object.assign({}, this.options.typeMetadata);
        this.changeDetector.markForCheck();
        this.history.getNewState();
    }
    /**
     * Removes descendant metadata from this component metadata
     * @param id - Id of descendant to be removed
     */
    removeDescendant(id) {
        var _a, _b, _c, _d, _e, _f;
        if (!this.options) {
            return;
        }
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('LayoutDesignerSAComponent: Removing descendant {{@data}}', { data: { id: this.options.typeMetadata.id, child: id } });
        (_c = (_b = this.editorMetadata) === null || _b === void 0 ? void 0 : _b.removeDescendant) === null || _c === void 0 ? void 0 : _c.call(_b, id, this.options.typeMetadata.options);
        this.canDrop = (_f = (_e = (_d = this.editorMetadata) === null || _d === void 0 ? void 0 : _d.canDropMetadata) === null || _e === void 0 ? void 0 : _e.call(_d, this.options.typeMetadata.options)) !== null && _f !== void 0 ? _f : false;
        this.renderedType = Object.assign({}, this.options.typeMetadata);
        this.changeDetector.markForCheck();
        this.history.getNewState();
    }
    //######################### protected methods - template bindings #########################
    /**
     * Shows designer overlay
     * @param event - Mouse event that occured
     */
    showOverlay(event) {
        var _a, _b, _c, _d;
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.verbose('LayoutDesignerComponent: Showing overlay for {{@type}}', { type: { name: (_b = this.options) === null || _b === void 0 ? void 0 : _b.typeMetadata.name, id: (_c = this.options) === null || _c === void 0 ? void 0 : _c.typeMetadata.id } });
        event.preventDefault();
        event.stopPropagation();
        this.layoutEditorMetadataManager.highlightComponent((_d = this.options) === null || _d === void 0 ? void 0 : _d.typeMetadata.id);
    }
    /**
     * Hides designer overlay
     * @param event - Mouse event that occured
     */
    hideOverlay(event) {
        var _a, _b, _c;
        if (isPresent(this.parent)) {
            return;
        }
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.verbose('LayoutDesignerComponent: Hiding overlay for {{@type}}', { type: { name: (_b = this.options) === null || _b === void 0 ? void 0 : _b.typeMetadata.name, id: (_c = this.options) === null || _c === void 0 ? void 0 : _c.typeMetadata.id } });
        event.preventDefault();
        event.stopPropagation();
        this.layoutEditorMetadataManager.cancelHighlightedComponent();
    }
    /**
     * Marks component as selected
     * @param event - Event that occured
     */
    selectComponent(event) {
        event.preventDefault();
        event.stopPropagation();
        if (this.options) {
            this.layoutEditorMetadataManager.selectComponent(this.options.typeMetadata.id);
        }
    }
    /**
     * Unselects selected component
     * @param event - Event that occured
     */
    unselectComponent(event) {
        event.preventDefault();
        event.stopPropagation();
        this.layoutEditorMetadataManager.unselectComponent();
    }
    /**
     * Removes itself from tree
     */
    remove() {
        if (!this.parent || !this.options) {
            return;
        }
        this.parent.removeDescendant(this.options.typeMetadata.id);
    }
    //######################### protected methods - overrides #########################
    /**
     * @inheritdoc
     */
    onInit() {
        const _super = Object.create(null, {
            onInit: { get: () => super.onInit }
        });
        var _a, e_1, _b, _c;
        var _d, _e, _f, _g, _h, _j, _k;
        return __awaiter(this, void 0, void 0, function* () {
            yield _super.onInit.call(this);
            if (!this.options) {
                return;
            }
            this.options.typeMetadata.scope = this.scopeId;
            if ((_d = this.parent) === null || _d === void 0 ? void 0 : _d.options) {
                try {
                    for (var _l = true, _m = __asyncValues(this.iteratorSvc.getChildrenIteratorFor((_e = this.parent.options) === null || _e === void 0 ? void 0 : _e.typeMetadata)), _o; _o = yield _m.next(), _a = _o.done, !_a; _l = true) {
                        _c = _o.value;
                        _l = false;
                        const child = _c;
                        if (this.options.typeMetadata.id === child.metadata.id) {
                            this.index = child.index;
                            break;
                        }
                    }
                }
                catch (e_1_1) { e_1 = { error: e_1_1 }; }
                finally {
                    try {
                        if (!_l && !_a && (_b = _m.return)) yield _b.call(_m);
                    }
                    finally { if (e_1) throw e_1.error; }
                }
            }
            //TODO: optimize
            this.initSubscriptions.add(this.layoutEditorMetadataManager.selectedChange.subscribe(() => this.changeDetector.detectChanges()));
            this.initSubscriptions.add(this.layoutEditorMetadataManager.highlightedChange.subscribe(() => this.changeDetector.detectChanges()));
            this.editorMetadata = yield this.metadataExtractor.extractMetadata(this.options.typeMetadata);
            this.canDrop = (_h = (_g = (_f = this.editorMetadata) === null || _f === void 0 ? void 0 : _f.canDropMetadata) === null || _g === void 0 ? void 0 : _g.call(_f, this.options.typeMetadata.options)) !== null && _h !== void 0 ? _h : false;
            this.layoutEditorMetadataManager.registerLayoutDesignerComponent(this, this.options.typeMetadata.id, (_k = (_j = this.parent) === null || _j === void 0 ? void 0 : _j.options) === null || _k === void 0 ? void 0 : _k.typeMetadata.id);
        });
    }
    /**
     * @inheritdoc
     */
    onOptionsSet() {
        var _a, _b, _c;
        if (!this.options ||
            isEqual(this._typeMetadata, this.options.typeMetadata)) {
            return;
        }
        this.renderedType = Object.assign({}, this.options.typeMetadata);
        this._typeMetadata = extend(true, {}, this.options.typeMetadata);
        this.horizontal = (_c = (_b = (_a = this.editorMetadata) === null || _a === void 0 ? void 0 : _a.isHorizontalDrop) === null || _b === void 0 ? void 0 : _b.call(_a, this.options.typeMetadata.options)) !== null && _c !== void 0 ? _c : false;
        this.changeDetector.detectChanges();
    }
}
LayoutDesignerSAComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: LayoutDesignerSAComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Injector }, { token: i1.LayoutEditorMetadataExtractor }, { token: i1.LayoutEditorMetadataManager }, { token: i1.LayoutComponentsIteratorService }, { token: LAYOUT_HISTORY_MANAGER }, { token: SCOPE_ID, optional: true }, { token: LOGGER, optional: true }, { token: LayoutDesignerSAComponent, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Component });
LayoutDesignerSAComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.4", type: LayoutDesignerSAComponent, isStandalone: true, selector: "layout-designer-component", viewQueries: [{ propertyName: "designerElement", first: true, predicate: ["layoutDesigner"], descendants: true, static: true }, { propertyName: "dndCoreDesigner", first: true, predicate: ["dndCoreDesigner"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"designer-overlay\" \n     #layoutDesigner\n     #dndCore=\"dndCoreDesigner\"\n     [dndCoreDesigner]=\"{metadata: renderedType, parentId: parent?.renderedType?.id, index: index}\"\n     [dropzoneElement]=\"layoutDropzone\"\n     [dragDisabled]=\"dragDisabled\"\n     [dragSource]=\"dndCore.drag\"\n     [noHTML5Preview]=\"true\"\n     (dropMetadata)=\"addDescendant($event)\"\n     [copyDesignerStyles]=\"renderedType\"\n     (mouseleave)=\"hideOverlay($event)\"\n     (mouseover)=\"showOverlay($event)\"\n     (click)=\"selectComponent($event)\"\n     (dblclick)=\"unselectComponent($event)\">\n    <div class=\"designer-dropzone\"\n         #layoutDropzone\n         designerMinWidth\n         [canDrop]=\"canDrop\"\n         [editorMetadata]=\"editorMetadata\"\n         [horizontal]=\"parent?.horizontal ?? false\"\n         [dropTarget]=\"dndCore.dropzone\"\n         [isDropZone]=\"canDrop\">\n        <ng-template #renderer=\"layoutComponentRenderer\" [layoutComponentRenderer]=\"renderedType\" [layoutComponentRendererDisableTransformer]=\"true\"></ng-template>\n\n        <ng-container *ngIf=\"highlighted || selected\">\n            <div class=\"designer-overlay-border\"></div>\n            <div class=\"designer-overlay-layout\" [layoutDesignerOverlayFor]=\"renderer\"></div>\n\n            <div class=\"designer-overlay-title\"\n                 *bodyRender\n                 [positionTo]=\"layoutDesigner\"\n                 placement=\"TopStart\">{{renderedType?.displayName ?? editorMetadata?.metaInfo?.name ?? renderedType?.name}}</div>\n\n            <ng-container *ngIf=\"!!parent && parent.editorMetadata?.removeDescendant\">\n                <div *bodyRender\n                     class=\"designer-overlay-remove\"\n                     [positionTo]=\"layoutDesigner\"\n                     [offset]=\"{mainAxis: -18, alignmentAxis: -6}\"\n                     placement=\"TopEnd\"\n                     (click)=\"remove()\">\n                    <span class=\"fas fa-times\"></span>\n                </div>\n            </ng-container>\n        </ng-container>\n    </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: PositionToSADirective, selector: "[positionTo]", inputs: ["positionTo", "placement", "offset", "autoUpdate"], outputs: ["flip", "done"] }, { kind: "component", type: LayoutDesignerOverlayForSAComponent, selector: "[layoutDesignerOverlayFor]", inputs: ["layoutDesignerOverlayFor"] }, { kind: "directive", type: DesignerMinDimensionSADirective, selector: "[designerMinWidth]", inputs: ["horizontal", "canDrop", "editorMetadata"] }, { kind: "directive", type: CopyDesignerStylesSADirective, selector: "[copyDesignerStyles]", inputs: ["copyDesignerStyles"], exportAs: ["copyDesignerStyles"] }, { kind: "directive", type: LayoutComponentRendererSADirective, selector: "[layoutComponentRenderer]", inputs: ["layoutComponentRenderer", "layoutComponentRendererInjector", "layoutComponentRendererDisableTransformer"], outputs: ["layoutComponentRendererComponentChange", "componentElementChange"], exportAs: ["layoutComponentRenderer"] }, { kind: "directive", type: DesignerDropzoneSADirective, selector: ".designer-dropzone", inputs: ["isDropZone"] }, { kind: "directive", type: BodyRenderSADirective, selector: "[bodyRender]" }, { kind: "ngmodule", type: DndModule }, { kind: "directive", type: i3.DragSourceDirective, selector: "[dragSource]", inputs: ["dragSource", "dragSourceType", "dragSourceOptions", "noHTML5Preview"] }, { kind: "directive", type: i3.DropTargetDirective, selector: "[dropTarget]", inputs: ["dropTarget", "dropTargetTypes", "dropTargetType"] }, { kind: "ngmodule", type: LayoutDndCoreModule }, { kind: "directive", type: i4.DndCoreDesignerDirective, selector: "[dndCoreDesigner]", inputs: ["dropzoneElement", "dndCoreDesigner", "dragDisabled"], outputs: ["dropMetadata"], exportAs: ["dndCoreDesigner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: LayoutDesignerSAComponent, decorators: [{
            type: Component,
            args: [{ selector: 'layout-designer-component', standalone: true, imports: [
                        CommonModule,
                        PositionToSADirective,
                        LayoutEditorDragPreviewSAComponent,
                        LayoutDesignerOverlayForSAComponent,
                        DesignerMinDimensionSADirective,
                        CopyDesignerStylesSADirective,
                        LayoutComponentRendererSADirective,
                        DesignerDropzoneSADirective,
                        BodyRenderSADirective,
                        DndModule,
                        LayoutDndCoreModule,
                    ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"designer-overlay\" \n     #layoutDesigner\n     #dndCore=\"dndCoreDesigner\"\n     [dndCoreDesigner]=\"{metadata: renderedType, parentId: parent?.renderedType?.id, index: index}\"\n     [dropzoneElement]=\"layoutDropzone\"\n     [dragDisabled]=\"dragDisabled\"\n     [dragSource]=\"dndCore.drag\"\n     [noHTML5Preview]=\"true\"\n     (dropMetadata)=\"addDescendant($event)\"\n     [copyDesignerStyles]=\"renderedType\"\n     (mouseleave)=\"hideOverlay($event)\"\n     (mouseover)=\"showOverlay($event)\"\n     (click)=\"selectComponent($event)\"\n     (dblclick)=\"unselectComponent($event)\">\n    <div class=\"designer-dropzone\"\n         #layoutDropzone\n         designerMinWidth\n         [canDrop]=\"canDrop\"\n         [editorMetadata]=\"editorMetadata\"\n         [horizontal]=\"parent?.horizontal ?? false\"\n         [dropTarget]=\"dndCore.dropzone\"\n         [isDropZone]=\"canDrop\">\n        <ng-template #renderer=\"layoutComponentRenderer\" [layoutComponentRenderer]=\"renderedType\" [layoutComponentRendererDisableTransformer]=\"true\"></ng-template>\n\n        <ng-container *ngIf=\"highlighted || selected\">\n            <div class=\"designer-overlay-border\"></div>\n            <div class=\"designer-overlay-layout\" [layoutDesignerOverlayFor]=\"renderer\"></div>\n\n            <div class=\"designer-overlay-title\"\n                 *bodyRender\n                 [positionTo]=\"layoutDesigner\"\n                 placement=\"TopStart\">{{renderedType?.displayName ?? editorMetadata?.metaInfo?.name ?? renderedType?.name}}</div>\n\n            <ng-container *ngIf=\"!!parent && parent.editorMetadata?.removeDescendant\">\n                <div *bodyRender\n                     class=\"designer-overlay-remove\"\n                     [positionTo]=\"layoutDesigner\"\n                     [offset]=\"{mainAxis: -18, alignmentAxis: -6}\"\n                     placement=\"TopEnd\"\n                     (click)=\"remove()\">\n                    <span class=\"fas fa-times\"></span>\n                </div>\n            </ng-container>\n        </ng-container>\n    </div>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Injector }, { type: i1.LayoutEditorMetadataExtractor }, { type: i1.LayoutEditorMetadataManager }, { type: i1.LayoutComponentsIteratorService }, { type: i5.MetadataHistoryManager, decorators: [{
                    type: Inject,
                    args: [LAYOUT_HISTORY_MANAGER]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [SCOPE_ID]
                }] }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [LOGGER]
                }, {
                    type: Optional
                }] }, { type: LayoutDesignerSAComponent, decorators: [{
                    type: SkipSelf
                }, {
                    type: Optional
                }] }], propDecorators: { designerElement: [{
                type: ViewChild,
                args: ['layoutDesigner', { static: true }]
            }], dndCoreDesigner: [{
                type: ViewChild,
                args: ['dndCoreDesigner', { static: true }]
            }] } });
//# sourceMappingURL=layoutDesigner.component.js.map