import { __awaiter } from "tslib";
import { Directive, EventEmitter, Inject, Input, Optional, Output, ViewContainerRef } from '@angular/core';
import { LOGGER } from '@anglr/common';
import { addSimpleChange, DynamicItemLoader } from '@anglr/dynamic';
import { isPresent, nameof } from '@jscrpt/common';
import { RELATIONS_NODES_LOADER } from '../../misc/tokens';
import { RelationsNodeManager } from '../../services';
import { RelationsNodeRendererDirectiveOptions } from './relationsNodeRenderer.options';
import { MissingNodeBehavior } from './relationsNodeRenderer.types';
import * as i0 from "@angular/core";
import * as i1 from "../../services";
import * as i2 from "./relationsNodeRenderer.options";
import * as i3 from "@anglr/dynamic";
/**
 * Renderer for dynamic relations node
 */
export class RelationsNodeRendererSADirective {
    //######################### protected properties #########################
    /**
     * Instance of dynamically created component
     */
    get component() {
        if (!this.componentRef) {
            return null;
        }
        return this.componentRef.instance;
    }
    //######################### constructor #########################
    constructor(viewContainerRef, relationsNodeManager, loader, options, logger) {
        this.viewContainerRef = viewContainerRef;
        this.relationsNodeManager = relationsNodeManager;
        this.loader = loader;
        this.options = options;
        this.logger = logger;
        //######################### protected properties #########################
        /**
         * Destroy subscription
         */
        this.destroySubscription = null;
        /**
         * Created component reference
         */
        this.componentRef = null;
        //######################### public properties - inputs #########################
        /**
         * Type that should be dynamically created into current container
         */
        this.componentMetadata = null;
        /**
         * Editor zoom level
         */
        this.zoomLevel = 1;
        //######################### public properties - outputs #########################
        /**
         * Occurs when rendered node is created
         */
        this.create = new EventEmitter();
        /**
         * Occurs when rendered node is destroyed
         */
        this.destroy = new EventEmitter();
        if (!this.options || !(this.options instanceof RelationsNodeRendererDirectiveOptions)) {
            this.options = new RelationsNodeRendererDirectiveOptions();
        }
    }
    //######################### public methods - implementation of OnChanges #########################
    /**
     * Called when input value changes
     */
    ngOnChanges(changes) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        return __awaiter(this, void 0, void 0, function* () {
            //only zoom level changed
            if (nameof('zoomLevel') in changes && isPresent(this.zoomLevel) &&
                !(nameof('componentMetadata') in changes)) {
                const component = this.component;
                //component is created
                if (component) {
                    const zoomChanges = changes[nameof('zoomLevel')];
                    component.zoomLevel = this.zoomLevel;
                    const chngs = {};
                    addSimpleChange(chngs, 'zoomLevel', zoomChanges, zoomChanges.previousValue);
                    component.ngOnChanges(chngs);
                    component.invalidateVisuals();
                }
                return;
            }
            (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug('RelationsNodeRendererSADirective: rendering node {{@id}}', { id: (_b = this.componentMetadata) === null || _b === void 0 ? void 0 : _b.id });
            this.ngOnDestroy();
            this.viewContainerRef.clear();
            // component metadata is present
            if (nameof('componentMetadata') in changes && this.componentMetadata) {
                let layoutComponentType = yield this.loader.loadItem(this.componentMetadata);
                if (!layoutComponentType) {
                    (_c = this.logger) === null || _c === void 0 ? void 0 : _c.warn('RelationsNodeRendererSADirective: Unable to find relations node type {{@type}}', { type: { name: this.componentMetadata.name, package: this.componentMetadata.package } });
                    switch ((_d = this.options) === null || _d === void 0 ? void 0 : _d.missingNodeBehavior) {
                        default:
                            //case MissingNodeBehavior.ShowNotFound:
                            {
                                layoutComponentType = yield this.loader.loadItem({
                                    package: 'basic-components',
                                    name: 'notFound',
                                });
                                if (!layoutComponentType) {
                                    (_e = this.logger) === null || _e === void 0 ? void 0 : _e.error('RelationsNodeRendererSADirective: Unable to find not found node!');
                                    return;
                                }
                                break;
                            }
                        case MissingNodeBehavior.Ignore:
                            {
                                //do nothing
                                return;
                            }
                        case MissingNodeBehavior.ThrowError:
                            {
                                throw new Error(`RelationsNodeRendererSADirective: Unable to find relations node type Name: ${this.componentMetadata.name} Package: ${this.componentMetadata.package}`);
                            }
                    }
                }
                this.componentRef = this.viewContainerRef.createComponent(layoutComponentType.data, {
                    injector: this.viewContainerRef.injector,
                });
                (_f = this.logger) === null || _f === void 0 ? void 0 : _f.debug('RelationsNodeRendererSADirective: node rendered {{@id}}', { id: (_g = this.componentMetadata) === null || _g === void 0 ? void 0 : _g.id });
                if (this.component) {
                    const node = this.component;
                    this.destroySubscription = node.destroy.subscribe(() => this.ngOnDestroy());
                    (_h = this.logger) === null || _h === void 0 ? void 0 : _h.debug('RelationsNodeRendererSADirective: initializing node with metadata {{@id}}', { id: (_j = this.componentMetadata) === null || _j === void 0 ? void 0 : _j.id });
                    node.metadata = this.componentMetadata;
                    node.zoomLevel = this.zoomLevel;
                    const chngs = {};
                    addSimpleChange(chngs, 'metadata', this.componentMetadata, null, true);
                    addSimpleChange(chngs, 'zoomLevel', this.zoomLevel, null, true);
                    node.ngOnChanges(chngs);
                    yield node.initialize();
                    (_k = this.logger) === null || _k === void 0 ? void 0 : _k.debug('RelationsNodeRendererSADirective: invalidating node visuals {{@id}}', { id: (_l = this.componentMetadata) === null || _l === void 0 ? void 0 : _l.id });
                    node.invalidateVisuals();
                    this.componentRef.changeDetectorRef.markForCheck();
                    this.relationsNodeManager.registerNode(this.component);
                    this.create.next(node);
                }
            }
        });
    }
    //######################### public methods - implementation of OnDestroy #########################
    /**
     * Called when component is destroyed
     */
    ngOnDestroy() {
        var _a, _b, _c, _d;
        (_a = this.destroySubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
        this.destroySubscription = null;
        if (this.componentRef) {
            (_b = this.logger) === null || _b === void 0 ? void 0 : _b.debug('RelationsNodeRendererSADirective: destroying node {{@id}}', { id: (_c = this.componentMetadata) === null || _c === void 0 ? void 0 : _c.id });
            if (this.component) {
                if (this.componentMetadata) {
                    this.destroy.next(this.componentMetadata);
                }
                this.relationsNodeManager.unregisterNode(this.component);
            }
            (_d = this.componentRef) === null || _d === void 0 ? void 0 : _d.destroy();
            this.componentRef = null;
        }
    }
}
RelationsNodeRendererSADirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: RelationsNodeRendererSADirective, deps: [{ token: i0.ViewContainerRef }, { token: i1.RelationsNodeManager }, { token: RELATIONS_NODES_LOADER }, { token: i2.RelationsNodeRendererDirectiveOptions, optional: true }, { token: LOGGER, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
RelationsNodeRendererSADirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.4", type: RelationsNodeRendererSADirective, isStandalone: true, selector: "[relationsNodeRenderer]", inputs: { componentMetadata: ["relationsNodeRenderer", "componentMetadata"], zoomLevel: "zoomLevel" }, outputs: { create: "create", destroy: "destroy" }, exportAs: ["relationsNodeRenderer"], usesOnChanges: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: RelationsNodeRendererSADirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[relationsNodeRenderer]',
                    standalone: true,
                    exportAs: 'relationsNodeRenderer'
                }]
        }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i1.RelationsNodeManager }, { type: i3.DynamicItemLoader, decorators: [{
                    type: Inject,
                    args: [RELATIONS_NODES_LOADER]
                }] }, { type: i2.RelationsNodeRendererDirectiveOptions, decorators: [{
                    type: Optional
                }] }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [LOGGER]
                }, {
                    type: Optional
                }] }], propDecorators: { componentMetadata: [{
                type: Input,
                args: ['relationsNodeRenderer']
            }], zoomLevel: [{
                type: Input
            }], create: [{
                type: Output
            }], destroy: [{
                type: Output
            }] } });
//# sourceMappingURL=relationsNodeRenderer.directive.js.map