import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import * as i0 from "@angular/core";
//TODO: logging
/**
 * Class used for handling relations nodes metadata
 */
export class RelationsNodeManager {
    constructor() {
        /**
         * Registered relations nodes
         */
        this._nodes = {};
        /**
         * Waiting input relations to be processed when node is created
         */
        this._waitingInputRelations = {};
        /**
         * Used for emitting node registration
         */
        this._nodesChange = new Subject();
        /**
         * Used for emitting active node change
         */
        this._activeNodeChange = new Subject();
        /**
         * Used for emitting node registration change
         */
        this._nodeRegisterChange = new Subject();
        /**
         * Used for emitting node unregistration change
         */
        this._nodeUnregisterChange = new Subject();
    }
    //######################### public properties #########################
    /**
     * Registered relation nodes
     */
    get nodes() {
        return this._nodes;
    }
    /**
     * Occurs when new node is registered
     */
    get nodesChange() {
        return this._nodesChange.asObservable();
    }
    /**
     * Active relations node
     */
    get activeNode() {
        return this._activeNode;
    }
    /**
     * Occurs when active relations node is changed
     */
    get activeNodeChange() {
        return this._activeNodeChange.asObservable();
    }
    /**
     * Occurs when registered node is changed
     */
    get nodeRegisterChange() {
        return this._nodeRegisterChange.asObservable();
    }
    /**
     * Occurs when unregistered node is changed
     */
    get nodeUnregisterChange() {
        return this._nodeUnregisterChange.asObservable();
    }
    //######################### public methods #########################
    /**
     * Sets active relation input
     * @param input - Component that represents input
     */
    setActiveInput(input) {
        this._activeInput = input;
    }
    /**
     * Gets active relation input
     */
    getActiveInput() {
        return this._activeInput;
    }
    /**
     * Registers node into manager
     * @param node - Node to be registered
     */
    registerNode(node) {
        var _a, _b;
        this._nodes[node.id] = node;
        this._nodesChange.next();
        this._nodeRegisterChange.next(node);
        //iterate over all outputs
        if (node.metadata?.outputs && Array.isArray(node.metadata?.outputs)) {
            for (const output of node.metadata?.outputs) {
                //no inputs
                if (!output.inputs || !Array.isArray(output.inputs)) {
                    continue;
                }
                const outputNode = node.outputs[output.outputName];
                //no output node
                if (!outputNode) {
                    continue;
                }
                for (const input of output.inputs) {
                    const relationsNode = this._nodes[input.id];
                    const relation = outputNode.startRelation();
                    //input node does not exists yet
                    if (!relationsNode) {
                        (_a = this._waitingInputRelations)[_b = input.id] ?? (_a[_b] = []);
                        this._waitingInputRelations[input.id].push({
                            inputName: input.inputName,
                            relation: relation,
                        });
                        continue;
                    }
                    const inputNode = relationsNode.inputs[input.inputName];
                    if (!inputNode) {
                        continue;
                    }
                    inputNode.endRelation(relation);
                }
            }
        }
        //finalize waiting inputs
        if (this._waitingInputRelations[node.id]) {
            const waitingInputRelations = this._waitingInputRelations[node.id];
            const inputNode = this._nodes[node.id];
            if (!inputNode) {
                return;
            }
            for (const waiting of waitingInputRelations) {
                const input = inputNode.inputs[waiting.inputName];
                if (!input) {
                    continue;
                }
                input.endRelation(waiting.relation);
                delete this._waitingInputRelations[node.id];
            }
        }
    }
    /**
     * Unregisters node from manager
     * @param node - Node to be unregistered
     */
    unregisterNode(node) {
        delete this._nodes[node.id];
        this._nodesChange.next();
        this._nodeUnregisterChange.next(node);
    }
    /**
     * Gets current metadata
     */
    getMetadata() {
        const result = [];
        const nodeIds = Object.keys(this._nodes);
        for (const id of nodeIds) {
            const node = this._nodes[id];
            if (!node.metadata) {
                continue;
            }
            const nodeMeta = {
                id,
                name: node.metadata.name,
                package: node.metadata.package,
                displayName: node.metadata.displayName,
                relationsOptions: node.metadata.relationsOptions,
                nodeMetadata: node.metadata.nodeMetadata,
                scope: node.metadata.scope,
                outputs: []
            };
            if (!node.allOutputs) {
                continue;
            }
            for (const output of node.allOutputs) {
                if (!output.relations) {
                    continue;
                }
                if (!output.name) {
                    continue;
                }
                const outputMeta = {
                    outputName: output.name,
                    inputs: []
                };
                for (const relation of output.relations) {
                    if (!relation.input?.name) {
                        continue;
                    }
                    outputMeta.inputs.push({
                        id: relation.input.parentId,
                        inputName: relation.input.name
                    });
                }
                nodeMeta.outputs?.push(outputMeta);
            }
            result.push(nodeMeta);
        }
        return result;
    }
    /**
     * Sets active relations node
     * @param id node identifier
     */
    setActiveNode(id) {
        this._activeNode = id;
        this._activeNodeChange.next();
    }
}
RelationsNodeManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: RelationsNodeManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
RelationsNodeManager.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: RelationsNodeManager });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.4", ngImport: i0, type: RelationsNodeManager, decorators: [{
            type: Injectable
        }] });
//# sourceMappingURL=relationsNodeManager.service.js.map