private static void CreateOrUpdateAbstractNodeFromConcreteNode(
            ConcreteNode srcNode,
            Cluster cluster,
            ref int abstractNodeId,
            int level,
            Dictionary <Id <ConcreteNode>, AbstractNodeInfo> abstractNodes)
        {
            AbstractNodeInfo abstractNodeInfo;

            if (!abstractNodes.TryGetValue(srcNode.NodeId, out abstractNodeInfo))
            {
                cluster.AddEntrance(
                    Id <AbstractNode> .From(abstractNodeId),
                    new Position(srcNode.Info.Position.X - cluster.Origin.X, srcNode.Info.Position.Y - cluster.Origin.Y));

                abstractNodeInfo = new AbstractNodeInfo(
                    Id <AbstractNode> .From(abstractNodeId),
                    level,
                    cluster.Id,
                    new Position(srcNode.Info.Position.X, srcNode.Info.Position.Y),
                    srcNode.NodeId);
                abstractNodes[srcNode.NodeId] = abstractNodeInfo;

                abstractNodeId++;
            }
            else if (level > abstractNodeInfo.Level)
            {
                abstractNodeInfo.Level = level;
            }
        }
        // insert a new node, such as start or target, to the abstract graph and
        // returns the id of the newly created node in the abstract graph
        // x and y are the positions where I want to put the node
        private Id <AbstractNode> InsertNodeIntoHierarchicalMap(HierarchicalMap map, Id <ConcreteNode> concreteNodeId, Position pos)
        {
            // If the node already existed (for instance, it was the an entrance point already
            // existing in the graph, we need to keep track of the previous status in order
            // to be able to restore it once we delete this STAL
            if (map.ConcreteNodeIdToAbstractNodeIdMap.ContainsKey(concreteNodeId))
            {
                var existingAbstractNodeId = map.ConcreteNodeIdToAbstractNodeIdMap[concreteNodeId];
                var nodeBackup             = new NodeBackup(
                    map.AbstractGraph.GetNodeInfo(existingAbstractNodeId).Level,
                    map.GetNodeEdges(concreteNodeId));
                nodeBackups[existingAbstractNodeId] = nodeBackup;
                return(map.ConcreteNodeIdToAbstractNodeIdMap[concreteNodeId]);
            }

            var cluster = map.FindClusterForPosition(pos);

            // create global entrance
            var abstractNodeId = Id <AbstractNode> .From(map.NrNodes);

            var entrance = cluster.AddEntrance(abstractNodeId, new Position(pos.X - cluster.Origin.X, pos.Y - cluster.Origin.Y));

            cluster.UpdatePathsForLocalEntrance(entrance);

            map.ConcreteNodeIdToAbstractNodeIdMap[concreteNodeId] = abstractNodeId;

            var info = new AbstractNodeInfo(
                abstractNodeId,
                1,
                cluster.Id,
                pos,
                concreteNodeId);

            map.AbstractGraph.AddNode(abstractNodeId, info);

            foreach (var entrancePoint in cluster.EntrancePoints)
            {
                if (cluster.AreConnected(abstractNodeId, entrancePoint.AbstractNodeId))
                {
                    map.AddEdge(
                        entrancePoint.AbstractNodeId,
                        abstractNodeId,
                        cluster.GetDistance(entrancePoint.AbstractNodeId, abstractNodeId));
                    map.AddEdge(
                        abstractNodeId,
                        entrancePoint.AbstractNodeId,
                        cluster.GetDistance(abstractNodeId, entrancePoint.AbstractNodeId));
                }
            }

            return(abstractNodeId);
        }
        public void AddEdgesToOtherEntrancesInCluster(AbstractNodeInfo abstractNodeInfo, int level)
        {
            SetCurrentLevelForSearches(level - 1);
            SetCurrentClusterByPositionAndLevel(abstractNodeInfo.Position, level);

            foreach (var cluster in Clusters)
            {
                if (cluster.Origin.X >= currentClusterX0 && cluster.Origin.X <= currentClusterX1 &&
                    cluster.Origin.Y >= currentClusterY0 && cluster.Origin.Y <= currentClusterY1)
                {
                    foreach (var entrance in cluster.EntrancePoints)
                    {
                        if (abstractNodeInfo.Id == entrance.AbstractNodeId || !IsValidAbstractNodeForLevel(entrance.AbstractNodeId, level))
                        {
                            continue;
                        }

                        AddEdgesBetweenAbstractNodes(abstractNodeInfo.Id, entrance.AbstractNodeId, level);
                    }
                }
            }
        }