import { __asyncValues, __awaiter, __decorate, __metadata } from "tslib";
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, ViewChildren, QueryList } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { DebounceCall, WithSync } from '@jscrpt/common';
import { DndModule } from '@ng-dnd/core';
import { Subscription, timer } from 'rxjs';
import { DragActiveService, LayoutComponentsIteratorService, LayoutEditorMetadataManager } from '../../../services';
import { LayoutDndCoreModule } from '../../../modules';
import { DesignerDropzoneSADirective } from '../../../directives';
import * as i0 from "@angular/core";
import * as i1 from "../../../services";
import * as i2 from "@angular/common";
import * as i3 from "@angular/material/button";
import * as i4 from "@ng-dnd/core";
import * as i5 from "../../../modules/layoutDndCore/directives/dndCoreTreeItem/dndCoreTreeItem.directive";
const DRAG_OVER_DELAY = 500;
/**
 * Component displaying components tree item
 */
export class ComponentsTreeItemSAComponent {
    //######################### protected fields - template bindings #########################
    /**
     * Indicates whether layout component has children
     * @param node layout component to check
     * @returns
     */
    get hasChildren() {
        return !!this.children && this.children.length > 0;
    }
    /**
     * Indication whether drag is disabled
     */
    get dragDisabled() {
        var _a;
        return !this.parentId || !this.data || ((_a = this._manager.getComponent(this.data.id)) === null || _a === void 0 ? void 0 : _a.dragDisabled) === true;
    }
    //######################### constructor #########################
    constructor(_manager, _changeDetector, _draggingSvc, iteratorSvc) {
        this._manager = _manager;
        this._changeDetector = _changeDetector;
        this._draggingSvc = _draggingSvc;
        this.iteratorSvc = iteratorSvc;
        //######################### protected fields #########################
        /**
         * Subscriptions created during initialization
         */
        this._initSubscriptions = new Subscription();
        /**
         * Node children
         */
        this.children = [];
        /**
         * Tree item index
         */
        this.index = 0;
        /**
         * Indication whether node is open
         */
        this.open = true;
    }
    //######################### public methods - implementation of OnInit #########################
    /**
     * Initialize component
     */
    ngOnInit() {
        this._initSubscriptions.add(this._manager.layoutChange.subscribe(() => {
            this.initChildren();
        }));
        this._initSubscriptions.add(this._manager.selectedChange.subscribe(() => {
            this._changeDetector.detectChanges();
        }));
        this._initSubscriptions.add(this._manager.highlightedChange.subscribe(() => this._changeDetector.detectChanges()));
        this._initSubscriptions.add(this._manager.displayNameChange.subscribe(() => this._changeDetector.detectChanges()));
        this._initSubscriptions.add(this._manager.draggedOverComponentChange.subscribe(() => this._handleDragOver()));
        this.initChildren();
    }
    //######################### public methods - implementation of OnDestroy #########################
    /**
     * Called when component is destroyed
     */
    ngOnDestroy() {
        this._initSubscriptions.unsubscribe();
    }
    //######################### public methods #########################
    /**
     * Toggle children visibility
     */
    toggle() {
        this.open = !this.open;
    }
    /**
     * Expands tree node
     * @param nodeId node identifier to expand
     * @returns indication whether node or its children were expanded
     */
    expand(nodeId) {
        var _a, _b;
        if (!nodeId) {
            this.open = true;
            return true;
        }
        if (((_a = this.data) === null || _a === void 0 ? void 0 : _a.id) === nodeId) {
            return true;
        }
        if (this.hasChildren) {
            for (const child of (_b = this._childrenNodes) === null || _b === void 0 ? void 0 : _b.toArray()) {
                if (child.expand(nodeId)) {
                    this.expand();
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * Adds descentant component metadata to this component metadata
     * @param dragData - Data from drag n drop event
     */
    addDescendant(dragData) {
        var _a;
        if (this.data) {
            (_a = this._manager.getComponent(this.data.id)) === null || _a === void 0 ? void 0 : _a.addDescendant(dragData);
        }
    }
    /**
     * Expands node and all its children
     */
    expandAll() {
        var _a;
        (_a = this._childrenNodes) === null || _a === void 0 ? void 0 : _a.forEach((child) => child.expandAll());
        this.expand();
        this._changeDetector.detectChanges();
    }
    /**
     * Collapse tree node
     */
    collapse() {
        this.open = false;
    }
    /**
     * Collapse node and all its children
     */
    collapseAll() {
        var _a;
        (_a = this._childrenNodes) === null || _a === void 0 ? void 0 : _a.forEach((child) => child.collapseAll());
        this.collapse();
        this._changeDetector.detectChanges();
    }
    //######################### protected methods #########################
    initChildren() {
        var _a, e_1, _b, _c;
        return __awaiter(this, void 0, void 0, function* () {
            this.children = [];
            if (this.data) {
                try {
                    for (var _d = true, _e = __asyncValues(this.iteratorSvc.getChildrenIteratorFor(this.data)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
                        _c = _f.value;
                        _d = false;
                        const child = _c;
                        this.children.push(child.metadata);
                    }
                }
                catch (e_1_1) { e_1 = { error: e_1_1 }; }
                finally {
                    try {
                        if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
                    }
                    finally { if (e_1) throw e_1.error; }
                }
            }
            this._changeDetector.detectChanges();
        });
    }
    //######################### protected methods - template bindings #########################
    /**
     * Highlights component
     * @param event - Mouse event that occured
     * @param id - Id of component that is highlighted
     */
    highlight(event, id) {
        event.preventDefault();
        event.stopPropagation();
        this._manager.highlightComponent(id);
    }
    /**
     * Handle event when user is dragging over this components
     */
    _handleDragOver() {
        var _a, _b;
        if (this._manager.draggedOverComponent != ((_a = this.data) === null || _a === void 0 ? void 0 : _a.id)) {
            (_b = this.dragOverSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
            this.dragOverSubscription = null;
            return;
        }
        if (!this.open) {
            this.dragOverSubscription = timer(DRAG_OVER_DELAY).subscribe(() => {
                this.expand();
                this._changeDetector.detectChanges();
            });
        }
    }
    //######################### protected methods - host #########################
    /**
     * Cancels highlight of component
     * @param event - Mouse event that occured
     */
    _cancelHighlight(event) {
        event.preventDefault();
        event.stopPropagation();
        this._manager.cancelHighlightedComponent();
    }
}
ComponentsTreeItemSAComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: ComponentsTreeItemSAComponent, deps: [{ token: i1.LayoutEditorMetadataManager }, { token: i0.ChangeDetectorRef }, { token: i1.DragActiveService }, { token: i1.LayoutComponentsIteratorService }], target: i0.ɵɵFactoryTarget.Component });
ComponentsTreeItemSAComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.4", type: ComponentsTreeItemSAComponent, isStandalone: true, selector: "components-tree-item", inputs: { data: "data", index: "index", parentId: "parentId", open: "open" }, host: { listeners: { "mouseleave": "_cancelHighlight($event)" } }, viewQueries: [{ propertyName: "_childrenNodes", predicate: ComponentsTreeItemSAComponent, descendants: true }], exportAs: ["componentsTreeItem"], ngImport: i0, template: "<div\n    #dndCoreTree=\"dndCoreTreeItem\"\n    #dropzone\n    [dndCoreTreeItem]=\"{metadata: data, parentId: parentId, index: index}\"\n    [dropzoneElement]=\"dropzone\"\n    [containerElement]=\"childrenContainer\"\n    [dragDisabled]=\"dragDisabled\"\n    [dragSource]=\"dndCoreTree.drag\"\n    [noHTML5Preview]=\"true\"\n    (dropMetadata)=\"addDescendant($event)\">\n\n    <div \n        class=\"designer-dropzone\" \n        [dropTarget]=\"dndCoreTree.dropzone\">\n        <div class=\"flex dynamic-align-items-center\" [ngClass]=\"hasChildren ? 'nested-node-tree' : 'node-tree'\">\n            <button type=\"button\" mat-icon-button [disabled]=\"!hasChildren\" (click)=\"toggle()\"\n                [attr.aria-label]=\"'Toggle'\">\n                <span class=\"fa\" *ngIf=\"hasChildren\" [ngClass]=\"open ? 'fa-chevron-down' : 'fa-chevron-right'\"></span>\n            </button>\n            <div \n                [class.selected]=\"data?.id === _manager.selectedComponent\"\n                [class.highlighted]=\"data?.id === _manager.highlightedComponent\"\n                (mouseover)=\"highlight($event, data?.id)\"\n                (click)=\"_manager.selectComponent(data?.id)\">{{data?.displayName || data?.id}}</div>\n        </div>\n    \n        <div \n            #childrenContainer\n            class=\"node-children\"\n            [class.hidden]=\"!open\">\n            <div \n                *ngFor=\"let child of children; let i = index;\"\n                class=\"node-child\">\n                <components-tree-item \n                    [data]=\"child\"\n                    [parentId]=\"data?.id\"\n                    [index]=\"i\"></components-tree-item>\n            </div>\n        </div>\n    </div>    \n</div>\n", dependencies: [{ kind: "component", type: ComponentsTreeItemSAComponent, selector: "components-tree-item", inputs: ["data", "index", "parentId", "open"], exportAs: ["componentsTreeItem"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: DndModule }, { kind: "directive", type: i4.DragSourceDirective, selector: "[dragSource]", inputs: ["dragSource", "dragSourceType", "dragSourceOptions", "noHTML5Preview"] }, { kind: "directive", type: i4.DropTargetDirective, selector: "[dropTarget]", inputs: ["dropTarget", "dropTargetTypes", "dropTargetType"] }, { kind: "ngmodule", type: LayoutDndCoreModule }, { kind: "directive", type: i5.DndCoreTreeItemDirective, selector: "[dndCoreTreeItem]", inputs: ["dropzoneElement", "containerElement", "dndCoreTreeItem", "dragDisabled"], outputs: ["dropMetadata"], exportAs: ["dndCoreTreeItem"] }, { kind: "directive", type: DesignerDropzoneSADirective, selector: ".designer-dropzone", inputs: ["isDropZone"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
__decorate([
    DebounceCall(10),
    WithSync(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], ComponentsTreeItemSAComponent.prototype, "initChildren", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: ComponentsTreeItemSAComponent, decorators: [{
            type: Component,
            args: [{ selector: 'components-tree-item', exportAs: 'componentsTreeItem', standalone: true, imports: [
                        CommonModule,
                        MatButtonModule,
                        DndModule,
                        LayoutDndCoreModule,
                        DesignerDropzoneSADirective,
                    ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n    #dndCoreTree=\"dndCoreTreeItem\"\n    #dropzone\n    [dndCoreTreeItem]=\"{metadata: data, parentId: parentId, index: index}\"\n    [dropzoneElement]=\"dropzone\"\n    [containerElement]=\"childrenContainer\"\n    [dragDisabled]=\"dragDisabled\"\n    [dragSource]=\"dndCoreTree.drag\"\n    [noHTML5Preview]=\"true\"\n    (dropMetadata)=\"addDescendant($event)\">\n\n    <div \n        class=\"designer-dropzone\" \n        [dropTarget]=\"dndCoreTree.dropzone\">\n        <div class=\"flex dynamic-align-items-center\" [ngClass]=\"hasChildren ? 'nested-node-tree' : 'node-tree'\">\n            <button type=\"button\" mat-icon-button [disabled]=\"!hasChildren\" (click)=\"toggle()\"\n                [attr.aria-label]=\"'Toggle'\">\n                <span class=\"fa\" *ngIf=\"hasChildren\" [ngClass]=\"open ? 'fa-chevron-down' : 'fa-chevron-right'\"></span>\n            </button>\n            <div \n                [class.selected]=\"data?.id === _manager.selectedComponent\"\n                [class.highlighted]=\"data?.id === _manager.highlightedComponent\"\n                (mouseover)=\"highlight($event, data?.id)\"\n                (click)=\"_manager.selectComponent(data?.id)\">{{data?.displayName || data?.id}}</div>\n        </div>\n    \n        <div \n            #childrenContainer\n            class=\"node-children\"\n            [class.hidden]=\"!open\">\n            <div \n                *ngFor=\"let child of children; let i = index;\"\n                class=\"node-child\">\n                <components-tree-item \n                    [data]=\"child\"\n                    [parentId]=\"data?.id\"\n                    [index]=\"i\"></components-tree-item>\n            </div>\n        </div>\n    </div>    \n</div>\n" }]
        }], ctorParameters: () => [{ type: i1.LayoutEditorMetadataManager }, { type: i0.ChangeDetectorRef }, { type: i1.DragActiveService }, { type: i1.LayoutComponentsIteratorService }], propDecorators: { _childrenNodes: [{
                type: ViewChildren,
                args: [ComponentsTreeItemSAComponent]
            }], data: [{
                type: Input
            }], index: [{
                type: Input
            }], parentId: [{
                type: Input
            }], open: [{
                type: Input
            }], initChildren: [], _cancelHighlight: [{
                type: HostListener,
                args: ['mouseleave', ['$event']]
            }] } });
//# sourceMappingURL=componentsTreeItem.component.js.map