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
     */
    async ngOnChanges(changes) {
        //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;
        }
        this.logger?.debug('RelationsNodeRendererSADirective: rendering node {{@id}}', { id: this.componentMetadata?.id });
        this.ngOnDestroy();
        this.viewContainerRef.clear();
        // component metadata is present
        if (nameof('componentMetadata') in changes && this.componentMetadata) {
            let layoutComponentType = await this.loader.loadItem(this.componentMetadata);
            if (!layoutComponentType) {
                this.logger?.warn('RelationsNodeRendererSADirective: Unable to find relations node type {{@type}}', { type: { name: this.componentMetadata.name, package: this.componentMetadata.package } });
                switch (this.options?.missingNodeBehavior) {
                    default:
                        //case MissingNodeBehavior.ShowNotFound:
                        {
                            layoutComponentType = await this.loader.loadItem({
                                package: 'basic-components',
                                name: 'notFound',
                            });
                            if (!layoutComponentType) {
                                this.logger?.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,
            });
            this.logger?.debug('RelationsNodeRendererSADirective: node rendered {{@id}}', { id: this.componentMetadata?.id });
            if (this.component) {
                const node = this.component;
                this.destroySubscription = node.destroy.subscribe(() => this.ngOnDestroy());
                this.logger?.debug('RelationsNodeRendererSADirective: initializing node with metadata {{@id}}', { id: this.componentMetadata?.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);
                await node.initialize();
                this.logger?.debug('RelationsNodeRendererSADirective: invalidating node visuals {{@id}}', { id: this.componentMetadata?.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() {
        this.destroySubscription?.unsubscribe();
        this.destroySubscription = null;
        if (this.componentRef) {
            this.logger?.debug('RelationsNodeRendererSADirective: destroying node {{@id}}', { id: this.componentMetadata?.id });
            if (this.component) {
                if (this.componentMetadata) {
                    this.destroy.next(this.componentMetadata);
                }
                this.relationsNodeManager.unregisterNode(this.component);
            }
            this.componentRef?.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