import { Rect } from '../primitives/rect';
import { cloneObject } from '../utility/base-util';
var GraphForceNode = /** @class */ (function () {
    function GraphForceNode(gnNode) {
        /**
         * @private
         */
        this.velocityX = 0;
        /**
         * @private
         */
        this.velocityY = 0;
        /**
         * @private
         */
        this.nodes = [];
        this.graphNode = gnNode;
        var nNode = this.graphNode;
        var bounds = getGraphBounds(nNode);
        this.location = bounds.center;
        this.nodes = [];
        if (!gnNode.treeInfo.parents) {
            gnNode.treeInfo.parents = [];
        }
        if (!gnNode.treeInfo.children) {
            gnNode.treeInfo.children = [];
        }
        this.nodes = (gnNode.treeInfo.parents).concat(gnNode.treeInfo.children);
    }
    /**
     * applyChanges method\
     *
     * @returns {  void }    applyChanges method .\
     * @private
     */
    GraphForceNode.prototype.applyChanges = function () {
        this.graphNode.treeInfo.center = this.location;
    };
    return GraphForceNode;
}());
export { GraphForceNode };
/**
 * SymmetricalLayout
 */
var SymmetricLayout = /** @class */ (function () {
    function SymmetricLayout() {
        this.cdCOEF = 0.442;
        this.cfMAXVELOCITY = 50;
        this.cnMAXITERACTION = 1000;
        this.cnSPRINGLENGTH = 100;
        this.mszMaxForceVelocity = { width: this.cfMAXVELOCITY, height: this.cfMAXVELOCITY };
        /**
         * @private
         */
        this.springLength = 0;
        /**
         * @private
         */
        this.springFactor = this.cdCOEF;
        /**
         * @private
         */
        this.maxIteration = this.cnMAXITERACTION;
        this.springLength = this.cnSPRINGLENGTH;
    }
    /**
     *To destroy the layout
     *
     * @returns {void} To destroy the layout
     */
    SymmetricLayout.prototype.destroy = function () {
        /**
         * Destroys symmetricLayout
         */
    };
    SymmetricLayout.prototype.getModuleName = function () {
        return 'SymmetricalLayout';
    };
    SymmetricLayout.prototype.doGraphLayout = function (graphLayoutManager) {
        var graph = this.selectedNode;
        graph.treeInfo.Bounds = graphLayoutManager.getModelBounds(graphLayoutManager.nodes);
        var lstGraphNodes = graph.treeInfo.GraphNodes;
        var lstNodes = this.convertGraphNodes(lstGraphNodes);
        var count = lstNodes.length;
        count = Math.min(this.maxIteration, count * count * count);
        this.preLayoutNodes(lstNodes, graph.treeInfo.Bounds);
        for (var i = 0, nLenght = count; i < nLenght; i++) {
            this.makeSymmetricLayout(lstNodes);
            this.appendForces(lstNodes);
        }
        this.resetGraphPosition(lstNodes, graph);
    };
    SymmetricLayout.prototype.preLayoutNodes = function (lstNodes, rcBounds) {
        var fMaxSize = Math.max(rcBounds.width, rcBounds.height);
        var ptCenter = { x: fMaxSize / 2, y: fMaxSize / 2 };
        var dRotateAngle = 2 * Math.PI / lstNodes.length;
        var dAngle = dRotateAngle;
        for (var i = 0; i < lstNodes.length; i++) {
            var gnNode = lstNodes[parseInt(i.toString(), 10)];
            var forceNode = this.getForceNode(gnNode);
            forceNode.location = {
                x: ptCenter.x + fMaxSize * Number((Math.cos(dAngle)).toFixed(2)),
                y: ptCenter.y + fMaxSize * Number(Math.sin(dAngle).toFixed(2))
            };
            dAngle -= dRotateAngle;
        }
    };
    /**
     * doLayout method\
     *
     * @returns {  void }    doLayout method .\
     * @param {GraphLayoutManager} graphLayoutManager - provide the angle value.
     * @private
     */
    SymmetricLayout.prototype.doLayout = function (graphLayoutManager) {
        this.selectedNode = graphLayoutManager.selectedNode;
        this.doGraphLayout(graphLayoutManager);
    };
    SymmetricLayout.prototype.makeSymmetricLayout = function (lstNodes) {
        var forceNode;
        var force;
        for (var k = 0; k < lstNodes.length; k++) {
            var gnNode = lstNodes[parseInt(k.toString(), 10)];
            forceNode = this.getForceNode(gnNode);
            var nodes = forceNode.nodes;
            for (var l = 0; l < nodes.length; l++) {
                var gnChild = nodes[parseInt(l.toString(), 10)];
                this.calcNodesForce(forceNode, this.getForceNode(gnChild));
            }
            for (var i = 0, length_1 = nodes.length; i < length_1; i++) {
                if (length_1 < 2) {
                    break;
                }
                var vtx1 = this.getForceNode(nodes[parseInt(i.toString(), 10)]);
                var vtx2 = (i + 1 >= length_1) ? this.getForceNode(nodes[0]) : this.getForceNode((nodes[i + 1]));
                var angle = (360 / nodes.length / 2) * Math.PI / 180;
                var normalDistance = 2 * this.springLength * Math.sin(angle);
                this.calcRelatesForce(vtx1, vtx2, normalDistance);
            }
            for (var s = 0; s < lstNodes.length; s++) {
                var gnChild = lstNodes[parseInt(s.toString(), 10)];
                if (!collectionContains(gnChild.id, nodes) && gnChild.id !== gnNode.id) {
                    force = this.getForceNode(gnChild);
                    this.updateNeigbour(forceNode, force);
                }
            }
        }
    };
    SymmetricLayout.prototype.appendForces = function (lstNodes) {
        var gfnNode = null;
        for (var k = 0; k < lstNodes.length; k++) {
            var gnNode = lstNodes[parseInt(k.toString(), 10)];
            gfnNode = this.getForceNode(gnNode);
            var ptPoint = gfnNode.location;
            ptPoint.x += Math.min(gfnNode.velocityX, this.mszMaxForceVelocity.width);
            ptPoint.y += Math.min(gfnNode.velocityY, this.mszMaxForceVelocity.height);
            gfnNode.velocityX = 0;
            gfnNode.velocityY = 0;
            gfnNode.location = ptPoint;
        }
    };
    SymmetricLayout.prototype.resetGraphPosition = function (lstNodes, graph) {
        var szMin = { width: Number.MAX_VALUE, height: Number.MAX_VALUE };
        var gfnNode = null;
        var gnNode;
        for (var k = 0; k < lstNodes.length; k++) {
            gnNode = lstNodes[parseInt(k.toString(), 10)];
            gfnNode = this.getForceNode(gnNode);
            var ptLocation = {
                x: gfnNode.location.x - gnNode.actualSize.width / 2,
                y: gfnNode.location.y - gnNode.actualSize.height / 2
            };
            szMin.width = Math.min(szMin.width, ptLocation.x);
            szMin.height = Math.min(szMin.height, ptLocation.y);
        }
        for (var k = 0; k < lstNodes.length; k++) {
            gnNode = lstNodes[parseInt(k.toString(), 10)];
            gfnNode = this.getForceNode(gnNode);
            var ptLocation = gfnNode.location;
            ptLocation.x -= szMin.width - (graph.treeInfo.location ? graph.treeInfo.location.x : 0);
            ptLocation.y -= szMin.height - (graph.treeInfo.location ? graph.treeInfo.location.y : 0);
            gfnNode.location = ptLocation;
            gfnNode.applyChanges();
        }
    };
    SymmetricLayout.prototype.convertGraphNodes = function (lstNodes) {
        var lstToReturn = [];
        var keys = Object.keys(lstNodes);
        for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
            var k = keys_1[_i];
            var gnNode = lstNodes["" + k];
            var forceNode = new GraphForceNode(gnNode);
            gnNode.treeInfo.tag = forceNode;
            lstToReturn.push(gnNode);
        }
        return lstToReturn;
    };
    /**
     * getForceNode method\
     *
     * @returns {  GraphForceNode }    getForceNode method .\
     * @param {IGraphObject} gnNode - provide the angle value.
     * @private
     */
    SymmetricLayout.prototype.getForceNode = function (gnNode) {
        return gnNode.treeInfo.tag;
    };
    SymmetricLayout.prototype.updateNeigbour = function (vtSource, vtTarget) {
        if (vtTarget == null || vtSource == null) {
            return;
        }
        var distance = this.pointDistance(vtSource.location, vtTarget.location);
        var angle = this.lineAngle(vtSource.location, vtTarget.location);
        var normalDistance = (this.springLength * 0.9);
        if (distance < normalDistance) {
            this.calcForce(distance, normalDistance, angle, vtTarget);
        }
    };
    SymmetricLayout.prototype.lineAngle = function (pt1, pt2) {
        var radians = 0;
        var vx = pt2.x - pt1.x;
        var vy = pt2.y - pt1.y;
        if (vx === 0) {
            if (vy <= 0) {
                radians = (3.0 * Math.PI) / 2.0;
            }
            else {
                radians = Math.PI / 2.0;
            }
        }
        else if (vy === 0) {
            if (vx < 0) {
                radians = Math.PI;
            }
            else {
                radians = 0;
            }
        }
        else {
            radians = Math.atan(vy / vx);
            if (vx < 0 && vy > 0) {
                radians = Math.PI + radians;
            }
            else if (vx < 0 && vy < 0) {
                radians = Math.PI + radians;
            }
            else if (vx > 0 && vy < 0) {
                radians = 2.0 * Math.PI + radians;
            }
        }
        return radians;
    };
    SymmetricLayout.prototype.pointDistance = function (pt1, pt2) {
        var d = 0;
        var dx = pt2.x - pt1.x;
        var dy = pt2.y - pt1.y;
        var t = (dx * dx) + (dy * dy);
        d = Math.sqrt(t);
        return d;
    };
    SymmetricLayout.prototype.calcRelatesForce = function (vtSource, vtTarget, normalDistance) {
        var distance = this.pointDistance(vtSource.location, vtTarget.location);
        var angle = this.lineAngle(vtSource.location, vtTarget.location);
        if (distance < normalDistance) {
            this.calcForce(distance, normalDistance, angle, vtTarget);
        }
    };
    /**
     * @param nodeCollection
     * @param connectors
     * @param symmetricLayout
     * @param nameTable
     * @param layout
     * @param viewPort
     * @private
     */
    /**
     * updateLayout method\
     *
     * @returns {  void }    updateLayout method .\
     * @param {IGraphObject[]} nodeCollection - provide the angle value.
     * @param {IGraphObject[]} connectors - provide the connectors value.
     * @param {SymmetricLayout} symmetricLayout - provide the symmetricLayout value.
     * @param {Object} nameTable - provide the nameTable value.
     * @param {Layout} layout - provide the layout value.
     * @param {PointModel} viewPort - provide the viewPort value.
     * @private
     */
    SymmetricLayout.prototype.updateLayout = function (nodeCollection, connectors, symmetricLayout, nameTable, layout, viewPort) {
        var layoutManager = new GraphLayoutManager();
        layoutManager.updateLayout(nodeCollection, connectors, symmetricLayout, nameTable, layout, viewPort);
    };
    SymmetricLayout.prototype.calcNodesForce = function (vtSource, vtTarget) {
        var distance = this.pointDistance(vtSource.location, vtTarget.location);
        var angle = this.lineAngle(vtSource.location, vtTarget.location);
        if (distance > this.springLength || distance < this.springLength) {
            this.calcForce(distance, this.springLength, angle, vtTarget);
        }
    };
    SymmetricLayout.prototype.calcForce = function (distance, minDist, angle, vtTarget) {
        var count = vtTarget.nodes.length;
        var length = distance - minDist;
        var factor = this.springFactor / (count * count) * Math.sqrt(count);
        var fVelocity = length * factor;
        var fOffset = fVelocity;
        var offsetX = Math.cos(angle) * fOffset;
        var offsetY = Math.sin(angle) * fOffset;
        vtTarget.velocityX -= offsetX;
        vtTarget.velocityY -= offsetY;
    };
    return SymmetricLayout;
}());
export { SymmetricLayout };
var GraphLayoutManager = /** @class */ (function () {
    function GraphLayoutManager() {
        this.visitedStack = [];
        this.cycleEdgesCollection = [];
        this.graphObjects = [];
        this.passedNodes = [];
    }
    /**
     * @param nodeCollection
     * @param connectors
     * @param symmetricLayout
     * @param nameTable
     * @param layout
     * @param viewPort
     * @private
     */
    /**
     * updateLayout method\
     *
     * @returns {  boolean }    updateLayout method .\
     * @param {IGraphObject[]} nodeCollection - provide the nodeCollection value.
     * @param {IGraphObject[]} connectors - provide the nodeCollection value.
     * @param {SymmetricLayout} symmetricLayout - provide the nodeCollection value.
     * @param {Object} nameTable - provide the nodeCollection value.
     * @param {Layout} layout - provide the nodeCollection value.
     * @param {PointModel} viewPort - provide the nodeCollection value.
     * @private
     */
    GraphLayoutManager.prototype.updateLayout = function (nodeCollection, connectors, symmetricLayout, nameTable, layout, viewPort) {
        this.nameTable = nameTable;
        this.nodes = nodeCollection;
        this.connectors = connectors;
        var selectionList = nodeCollection;
        if (selectionList.length > 0) {
            this.mhelperSelectedNode = cloneObject(selectionList[0]);
        }
        for (var _i = 0, nodeCollection_1 = nodeCollection; _i < nodeCollection_1.length; _i++) {
            var node = nodeCollection_1[_i];
            var nodeGraphObject = node;
            nodeGraphObject.treeInfo = {};
            nodeGraphObject.treeInfo.graphType = 'Node';
            this.graphObjects.push(nodeGraphObject);
        }
        for (var _a = 0, connectors_1 = connectors; _a < connectors_1.length; _a++) {
            var connector = connectors_1[_a];
            var connectorGraphObject = connector;
            connectorGraphObject.treeInfo = {};
            connectorGraphObject.treeInfo.graphType = 'Connector';
            this.graphObjects.push(connectorGraphObject);
        }
        this.updateLayout1(this.graphObjects, symmetricLayout);
        var modelBounds = this.getModelBounds(selectionList);
        for (var i = 0; i < selectionList.length; i++) {
            var node = selectionList[parseInt(i.toString(), 10)];
            var trnsX = (viewPort.x - modelBounds.width) / 2;
            var margin = layout.margin;
            var dx = (node.treeInfo.tag.location.x - (node.offsetX - (node.actualSize.width / 2)) -
                modelBounds.x + trnsX + margin.left);
            var dy = (node.treeInfo.tag.location.y - (node.offsetY - (node.actualSize.height / 2)) - modelBounds.y + margin.top);
            node.offsetX += dx;
            node.offsetY += dy;
            delete node.treeInfo;
        }
        return true;
    };
    /**
     * getModelBounds method\
     *
     * @returns {  Rect }    getModelBounds method .\
     * @param {IGraphObject[]} lNodes - provide the angle value.
     * @private
     */
    GraphLayoutManager.prototype.getModelBounds = function (lNodes) {
        lNodes = lNodes.slice();
        var rect = null;
        var rect1 = null;
        var node;
        for (var i = 0; i < lNodes.length; i++) {
            node = lNodes[parseInt(i.toString(), 10)];
            var bounds = getGraphBounds(node);
            rect = new Rect(node.treeInfo.tag ? node.treeInfo.tag.location.x : bounds.x, node.treeInfo.tag ? node.treeInfo.tag.location.y : bounds.y, node.actualSize.width, node.actualSize.height);
            if (rect1) {
                rect1 = rect1.uniteRect(rect);
            }
            else {
                rect1 = rect;
            }
        }
        return rect1;
    };
    GraphLayoutManager.prototype.updateLayout1 = function (nodesToLayout, symmetricLayout) {
        this.detectCyclesInGraph(nodesToLayout);
        var nodesCount = nodesToLayout.length;
        if (nodesCount > 0) {
            var cycleConnColln = [];
            var nodes = [];
            var nodeSymbols = [];
            for (var s = 0; s < nodesToLayout.length; s++) {
                var nd = nodesToLayout[parseInt(s.toString(), 10)];
                if (nd.treeInfo.isCycleEdge === undefined) {
                    nd.treeInfo.isCycleEdge = false;
                }
                if (nd.treeInfo.graphType === 'Connector' && !nd.treeInfo.isCycleEdge) {
                    nodes.push(nd);
                }
                else if (nd.treeInfo.graphType === 'Connector') {
                    cycleConnColln.push(nd);
                }
                else {
                    nodeSymbols.push(nd);
                }
            }
            nodes = nodes.concat(nodeSymbols);
            nodes = cycleConnColln.concat(nodes);
            while (nodesCount > this.dictionaryLength(this.passedNodes)) {
                this.getNodesToPosition(nodes);
                if (this.selectedNode == null) {
                    continue;
                }
                symmetricLayout.doLayout(this);
                this.selectedNode = null;
                this.visitedStack = [];
            }
            this.passedNodes = null;
            this.selectedNode = null;
        }
        return false;
    };
    GraphLayoutManager.prototype.getNodesToPosition = function (nodes) {
        for (var i = 0; i < nodes.length; i++) {
            var node = nodes[parseInt(i.toString(), 10)];
            this.selectNodes(node);
            break;
        }
    };
    GraphLayoutManager.prototype.selectNodes = function (node) {
        var nodeGraph = node;
        if (node.treeInfo.graphType === 'Connector') {
            this.exploreGraphEdge(node);
        }
        else if (nodeGraph != null) {
            if (this.addNode(node, 'passed')) {
                this.addNode(node, 'selected');
                if (this.isConnectedToAnotherNode(nodeGraph)) {
                    this.selectedNode = { treeInfo: {} };
                    this.selectedNode.treeInfo.LeftMargin = 10;
                    this.selectedNode.treeInfo.TopMargin = 10;
                    this.selectConnectedNodes(nodeGraph);
                }
            }
        }
    };
    GraphLayoutManager.prototype.selectConnectedNodes = function (nodeGraph) {
        var graph = this.selectedNode;
        if (!graph.treeInfo.GraphNodes) {
            graph.treeInfo.GraphNodes = {};
        }
        var node = nodeGraph;
        this.addNode(node, 'passed');
        var nodeName = node.id;
        if (!this.dictionaryContains(graph.treeInfo.GraphNodes, node)) {
            var gnNode = this.addGraphNode(node);
            this.getConnectedRelatives(gnNode);
            this.exploreRelatives(nodeGraph);
        }
        else {
            var graphNode = graph.treeInfo.GraphNodes["" + nodeName];
            if (graphNode.treeInfo.Added) {
                graphNode.treeInfo.Added = false;
                this.getConnectedRelatives(graphNode);
                this.exploreRelatives(nodeGraph);
            }
        }
    };
    GraphLayoutManager.prototype.exploreRelatives = function (nodeGraph) {
        this.exploreRelatives1(nodeGraph, 'Parents');
        this.exploreRelatives1(nodeGraph, 'Children');
    };
    GraphLayoutManager.prototype.exploreRelatives1 = function (nodeGraph, relativesToExplore) {
        var edges = [];
        if (relativesToExplore === 'Parents') {
            edges = nodeGraph.inEdges;
        }
        else {
            edges = nodeGraph.outEdges;
        }
        for (var i = 0; i < edges.length; i++) {
            var edge = this.nameTable[edges[parseInt(i.toString(), 10)]];
            if (this.addNode(edge, 'passed')) {
                var fromNode = this.nameTable[edge.sourceID];
                var toNode = this.nameTable[edge.targetID];
                if (relativesToExplore === 'Parents' && fromNode != null &&
                    collectionContains(fromNode.id, this.nodes)) {
                    this.selectConnectedNodes(this.nameTable[edge.sourceID]);
                }
                else if (relativesToExplore === 'Children' && toNode != null &&
                    collectionContains(toNode.id, this.nodes)) {
                    this.selectConnectedNodes(this.nameTable[edge.targetID]);
                }
            }
        }
    };
    GraphLayoutManager.prototype.getConnectedRelatives = function (graphNode) {
        this.getConnectedParents(graphNode);
        this.getConnectedChildren(graphNode);
    };
    GraphLayoutManager.prototype.dictionaryContains = function (obj, keyObj) {
        var keys = Object.keys(obj);
        for (var i = 0; i < keys.length; i++) {
            if (keys[parseInt(i.toString(), 10)] === keyObj.id) {
                return true;
            }
        }
        return false;
    };
    GraphLayoutManager.prototype.dictionaryLength = function (obj) {
        var keys = Object.keys(obj);
        return keys.length;
    };
    GraphLayoutManager.prototype.getConnectedChildren = function (graphNode) {
        var graph = this.selectedNode;
        var nodeGraph = graphNode;
        for (var s = 0; s < nodeGraph.outEdges.length; s++) {
            var edge = this.nameTable[nodeGraph.outEdges[parseInt(s.toString(), 10)]];
            if (!edge.treeInfo.isCycleEdge) {
                var node = this.nameTable[edge.targetID];
                if (collectionContains(node.id, this.nodes) && node != null && node.visible) {
                    var gnNodeChildren = void 0;
                    if (!this.dictionaryContains(graph.treeInfo.GraphNodes, node)) {
                        gnNodeChildren = this.addGraphNode(node);
                        gnNodeChildren.treeInfo.Added = true;
                    }
                    else {
                        gnNodeChildren = graph.treeInfo.GraphNodes[node.id];
                    }
                    if (!graphNode.treeInfo.children) {
                        graphNode.treeInfo.children = [];
                    }
                    if (!gnNodeChildren.treeInfo.parents) {
                        gnNodeChildren.treeInfo.parents = [];
                    }
                    this.setNode(gnNodeChildren.treeInfo.parents, graphNode);
                    if (this.findNode(graphNode.treeInfo.children, gnNodeChildren.id) < 0) {
                        graphNode.treeInfo.children.push(gnNodeChildren);
                    }
                }
            }
        }
    };
    GraphLayoutManager.prototype.getConnectedParents = function (graphNode) {
        var graph = this.selectedNode;
        var nodeGraph = graphNode;
        for (var s = 0; s < nodeGraph.inEdges.length; s++) {
            var edge = this.nameTable[nodeGraph.inEdges[parseInt(s.toString(), 10)]];
            if (!edge.treeInfo.isCycleEdge) {
                var node = this.nameTable[edge.sourceID];
                if (collectionContains(node.id, this.nodes) && node != null && node.visible) {
                    var gnNode = void 0;
                    if (!this.dictionaryContains(graph.treeInfo.GraphNodes, node)) {
                        gnNode = this.addGraphNode(node);
                        gnNode.treeInfo.Added = true;
                    }
                    else {
                        gnNode = graph.treeInfo.GraphNodes[node.id];
                    }
                    if (!graphNode.treeInfo.parents) {
                        graphNode.treeInfo.parents = [];
                    }
                    if (!gnNode.treeInfo.children) {
                        gnNode.treeInfo.children = [];
                    }
                    this.setNode(gnNode.treeInfo.children, graphNode);
                    if (this.findNode(graphNode.treeInfo.parents, gnNode.id) < 0) {
                        graphNode.treeInfo.parents.push(gnNode);
                    }
                }
            }
        }
    };
    GraphLayoutManager.prototype.setNode = function (list, node) {
        var nIndex = this.findNode(list, node.id);
        if (nIndex >= 0 && nIndex < list.length) {
            list[parseInt(nIndex.toString(), 10)] = node;
        }
        else {
            list.push(node);
        }
    };
    GraphLayoutManager.prototype.findNode = function (list, fullName) {
        var nIndex = -1;
        if (list != null && fullName !== '') {
            for (var i = 0, nLength = list.length; i < nLength; i++) {
                var gnNode = list[parseInt(i.toString(), 10)];
                if (gnNode != null && gnNode.id === fullName) {
                    nIndex = i;
                    break;
                }
            }
        }
        return nIndex;
    };
    GraphLayoutManager.prototype.addGraphNode = function (node) {
        var graph = this.selectedNode;
        var gnNode = node;
        graph.treeInfo.GraphNodes[gnNode.id] = gnNode;
        var nodeHelper = this.mhelperSelectedNode;
        if (nodeHelper != null && node.id === nodeHelper.id) {
            this.mhelperSelectedNode = gnNode;
        }
        return gnNode;
    };
    GraphLayoutManager.prototype.isConnectedToAnotherNode = function (gnNode) {
        var bFoundConnectedNode = false;
        var edges = (gnNode.inEdges).concat(gnNode.outEdges);
        if (edges.length > 0) {
            if ((gnNode.inEdges != null) && (gnNode.inEdges.length > 0)) {
                bFoundConnectedNode = this.searchEdgeCollection(gnNode.inEdges, 'FromNode');
            }
            if ((!bFoundConnectedNode) && (gnNode.outEdges != null) && (gnNode.outEdges.length > 0)) {
                bFoundConnectedNode = this.searchEdgeCollection(gnNode.outEdges, 'ToNode');
            }
        }
        return bFoundConnectedNode;
    };
    GraphLayoutManager.prototype.searchEdgeCollection = function (edgesToSearchThrough, connectionDirection) {
        var bFoundConnectedNode = false;
        for (var i = 0; i < edgesToSearchThrough.length - 1; i++) {
            var edge = this.nameTable[edgesToSearchThrough[parseInt(i.toString(), 10)]];
            if (!this.addNode(edge, 'passed')) {
                continue;
            }
            if (!edge.treeInfo.isCycleEdge && ((connectionDirection === 'FromNode' && this.nameTable[edge.sourceID] != null)
                || (connectionDirection === 'ToNode' && this.nameTable[edge.targetID] != null))) {
                bFoundConnectedNode = true;
                break;
            }
        }
        return bFoundConnectedNode;
    };
    GraphLayoutManager.prototype.exploreGraphEdge = function (node) {
        var nodeLink = node;
        if (nodeLink != null && !nodeLink.treeInfo.isCycleEdge && this.addNode(node, 'passed')) {
            this.addNode(node, 'selected');
            var fromNode = this.nameTable[nodeLink.sourceID];
            var toNode = this.nameTable[nodeLink.targetID];
            if (fromNode != null) {
                this.selectNodes(fromNode);
            }
        }
    };
    GraphLayoutManager.prototype.addNode = function (nodeToAdd, collectionToAdd) {
        var bResult = true;
        var node = nodeToAdd;
        if (collectionToAdd === 'passed' || !node.visible) {
            if (!this.dictionaryContains(this.passedNodes, node)) {
                this.passedNodes[node.id] = node;
            }
        }
        if (!node.visible) {
            return false;
        }
        return bResult;
    };
    GraphLayoutManager.prototype.detectCyclesInGraph = function (nodes) {
        var vertex = [];
        var currentStack = [];
        for (var k = 0; k < nodes.length; k++) {
            if (!(nodes[parseInt(k.toString(), 10)].treeInfo.graphType === 'Connector')) {
                vertex.push(nodes[parseInt(k.toString(), 10)]);
            }
        }
        if (vertex.length > 0) {
            currentStack.push(vertex[0]);
            this.visitedStack.push(vertex[0]);
            while (currentStack.length > 0) {
                var top_1 = currentStack[currentStack.length - 1];
                var childNodes = this.getUnVisitedChildNodes(top_1);
                if (childNodes.length > 0) {
                    var child = childNodes[0];
                    var currentEdge = childNodes[childNodes.length - 1];
                    if (collectionContains(child.id, this.visitedStack)) {
                        currentEdge.treeInfo.isCycleEdge = true;
                        this.cycleEdgesCollection.push(currentEdge);
                    }
                    else {
                        currentStack.push(child);
                        this.visitedStack.splice(0, 0, child);
                    }
                }
                else {
                    currentStack.pop();
                }
            }
        }
    };
    GraphLayoutManager.prototype.getUnVisitedChildNodes = function (top) {
        var childNodes = [];
        if (top.outEdges.length > 0) {
            for (var i = 0; i < top.outEdges.length; i++) {
                var con = this.nameTable[top.outEdges[parseInt(i.toString(), 10)]];
                if (!collectionContains(con.id, this.visitedStack)) {
                    var toNode = this.nameTable[con.targetID];
                    if (toNode != null) {
                        childNodes.push(toNode);
                    }
                    childNodes.push(con);
                    this.visitedStack.splice(0, 0, con);
                    return childNodes;
                }
            }
            return childNodes;
        }
        return childNodes;
    };
    return GraphLayoutManager;
}());
export { GraphLayoutManager };
/**
 * getGraphBounds method\
 *
 * @returns {  void }    getGraphBounds method .\
 * @param {IGraphObject} node - provide the angle value.
 * @private
 */
function getGraphBounds(node) {
    var x = node.offsetX - node.actualSize.width * node.pivot.x;
    var y = node.offsetY - node.actualSize.height * node.pivot.y;
    return new Rect(x, y, node.actualSize.width, node.actualSize.height);
}
/**
 * @param id
 * @param coll
 */
/**
 * collectionContains method\
 *
 * @returns {  boolean }    collectionContains method .\
 * @param {string} id - provide the id value.
 * @param {IGraphObject[]} coll - provide the id value.
 * @private
 */
function collectionContains(id, coll) {
    for (var i = 0; i < coll.length; i++) {
        if (coll[parseInt(i.toString(), 10)].id === id) {
            return true;
        }
    }
    return false;
}
