Represents an entrance point between 2 clusters
        private List <Entrance> CreateEntrancesAlongEdge(
            int startPoint,
            int endPoint,
            Cluster precedentCluster,
            Cluster currentCluster,
            ref int currentEntranceId,
            Func <int, Tuple <ConcreteNode, ConcreteNode> > getNodesInEdge,
            Orientation orientation)
        {
            List <Entrance> entrances = new List <Entrance>();

            for (var entranceStart = startPoint; entranceStart <= endPoint; entranceStart++)
            {
                var size = GetEntranceSize(entranceStart, endPoint, getNodesInEdge);

                var entranceEnd = entranceStart + size - 1;
                if (size == 0)
                {
                    continue;
                }

                if (_entranceStyle == EntranceStyle.EndEntrance && size > MAX_ENTRANCE_WIDTH)
                {
                    var nodes    = getNodesInEdge(entranceStart);
                    var srcNode  = nodes.Item1;
                    var destNode = nodes.Item2;

                    var entrance1 = new Entrance(Id <Entrance> .From(currentEntranceId), precedentCluster, currentCluster, srcNode, destNode, orientation);

                    currentEntranceId++;

                    nodes    = getNodesInEdge(entranceEnd);
                    srcNode  = nodes.Item1;
                    destNode = nodes.Item2;

                    var entrance2 = new Entrance(Id <Entrance> .From(currentEntranceId), precedentCluster, currentCluster, srcNode, destNode, orientation);

                    currentEntranceId++;

                    entrances.Add(entrance1);
                    entrances.Add(entrance2);
                }
                else
                {
                    var nodes    = getNodesInEdge((entranceEnd + entranceStart) / 2);
                    var srcNode  = nodes.Item1;
                    var destNode = nodes.Item2;

                    var entrance = new Entrance(Id <Entrance> .From(currentEntranceId), precedentCluster, currentCluster, srcNode, destNode, orientation);

                    currentEntranceId++;
                    entrances.Add(entrance);
                }

                entranceStart = entranceEnd;
            }

            return(entrances);
        }
        private void CreateEntranceEdges(Entrance entrance, AbsType type)
        {
            var level = entrance.GetEntranceLevel(_clusterSize, _maxLevel);

            var srcAbstractNodeId  = _hierarchicalMap.ConcreteNodeIdToAbstractNodeIdMap[entrance.SrcNode.NodeId];
            var destAbstractNodeId = _hierarchicalMap.ConcreteNodeIdToAbstractNodeIdMap[entrance.DestNode.NodeId];

            var orientation = entrance.Orientation;
            int cost        = Constants.COST_ONE;

            switch (type)
            {
            case AbsType.ABSTRACT_TILE:
            case AbsType.ABSTRACT_OCTILE_UNICOST:
                // Inter-edges: cost 1
                cost = Constants.COST_ONE;
                break;

            case AbsType.ABSTRACT_OCTILE:
            {
                int unitCost;
                switch (orientation)
                {
                case Orientation.Horizontal:
                case Orientation.Vertical:
                    unitCost = Constants.COST_ONE;
                    break;

                case Orientation.Hdiag2:
                case Orientation.Hdiag1:
                case Orientation.Vdiag1:
                case Orientation.Vdiag2:
                    unitCost = (Constants.COST_ONE * 34) / 24;
                    break;

                default:
                    unitCost = -1;
                    break;
                }

                cost = unitCost;
            }
            break;
            }

            _hierarchicalMap.AbstractGraph.AddEdge(srcAbstractNodeId, destAbstractNodeId, new AbstractEdgeInfo(cost, level, true));
            _hierarchicalMap.AbstractGraph.AddEdge(destAbstractNodeId, srcAbstractNodeId, new AbstractEdgeInfo(cost, level, true));
        }
        private List<Entrance> CreateVertEntrances(int y0, int y1, int x, int clusterid1,
            int clusterid2, int currId, out int lastEntraceId)
        {
            var currentIdCounter = currId;
			var tilingGraph = ConcreteMap.Graph;
	        Func<int, int, Graph<TilingNodeInfo, TilingEdgeInfo>.Node> getNode =
		        (top, left) => tilingGraph.GetNode(ConcreteMap.GetNodeIdFromPos(top, left));

			List<Entrance> entrances = new List<Entrance>();

			for (var i = y0; i <= y1; i++)
            {
                var node1isObstacle = getNode(x, i).Info.IsObstacle;
                var node2isObstacle = getNode(x + 1, i).Info.IsObstacle;
                // get the next communication spot
                if (node1isObstacle || node2isObstacle)
                    continue;

                // start building the entrance
                var entranceStart = i;
                while (true)
                {
                    i++;
                    if (i >= y1)
                        break;
                    node1isObstacle = getNode(x, i).Info.IsObstacle;
                    node2isObstacle = getNode(x + 1, i).Info.IsObstacle;
                    if (node1isObstacle || node2isObstacle || i >= y1)
                        break;
                }

                if (EntranceStyle == EntranceStyle.END_ENTRANCE && (i - entranceStart) > MAX_ENTRANCE_WIDTH)
                {
                    // create two entrances, one for each end
                    var entrance1 = new Entrance(currentIdCounter++, clusterid1, clusterid2, entranceStart, x,
									   getNode(x, entranceStart).NodeId,
									   getNode(x + 1, entranceStart).NodeId, Orientation.VERTICAL);

                    // BEWARE! We are getting the tileNode for position i - 1. If clustersize was 8
                    // for example, and end would had finished at 7, you would set the entrance at 6.
                    // This seems to be intended.
                    var entrance2 = new Entrance(currentIdCounter++, clusterid1, clusterid2, (i - 1), x,
									   getNode(x, i - 1).NodeId,
                                       getNode(x + 1, i - 1).NodeId, Orientation.VERTICAL);

					entrances.Add(entrance1);
					entrances.Add(entrance2);
				}
                else
                {
                    // create one entrance
                    var entrance = new Entrance(currentIdCounter++, clusterid1, clusterid2, ((i - 1) + entranceStart) / 2, x,
									  getNode(x, (i - 1 + entranceStart) / 2).NodeId,
                                      getNode(x + 1, (i - 1 + entranceStart) / 2).NodeId, Orientation.VERTICAL);
					entrances.Add(entrance);
				}
            }

            lastEntraceId = currentIdCounter;
	        return entrances;
        }
        // TODO: Together with Vert Entrances, refactor the code, they are too similar!
        /// <summary>
        /// Creates the horizontal entrances between the two clusters, and returns the last entrance id
        /// </summary>
        private List<Entrance> CreateHorizEntrances(
            int x0,
            int x1,
            int y,
            int clusterid1,
            int clusterid2,
            int currId,
			out int nextId)
        {
            var currentIdCounter = currId;
            var orientation = Orientation.HORIZONTAL;
            
            var tilingGraph = ConcreteMap.Graph;
			Func<int, int, Graph<TilingNodeInfo, TilingEdgeInfo>.Node> getNode =
				(top, left) => tilingGraph.GetNode(ConcreteMap.GetNodeIdFromPos(top, left));

			List<Entrance> entrances = new List<Entrance>();

			// rolls over the horizontal edge between x0 and x1 in order to find edges between
			// the top cluster (latitude marks the other cluster entrance line)
			for (var i = x0; i <= x1; i++)
            {
                var node1isObstacle = getNode(i, y).Info.IsObstacle;
                var node2isObstacle = getNode(i, y + 1).Info.IsObstacle;
                // get the next communication spot
                if (node1isObstacle || node2isObstacle)
                    continue;

                // start building and tracking the entrance
                var entranceStart = i;
                while (true)
                {
                    i++;
                    if (i >= x1)
                        break;
                    node1isObstacle = getNode(i, y).Info.IsObstacle;
                    node2isObstacle = getNode(i, y + 1).Info.IsObstacle;
                    if (node1isObstacle || node2isObstacle || i >= x1)
                        break;
                }

                if (EntranceStyle == EntranceStyle.END_ENTRANCE && i - entranceStart > MAX_ENTRANCE_WIDTH)
                {
                    // If the tracked entrance is big, create 2 entrance points at the edges of the entrance.
                    // create two new entrances, one for each end
                    var entrance1 = new Entrance(currentIdCounter++, clusterid1, clusterid2, y, entranceStart,
									   getNode(entranceStart, y).NodeId,
									   getNode(entranceStart, y + 1).NodeId, orientation);

                    var entrance2 = new Entrance(currentIdCounter++, clusterid1, clusterid2, y, (i - 1),
									   getNode(i - 1, y).NodeId,
									   getNode(i - 1, y + 1).NodeId, orientation);

					entrances.Add(entrance1);
					entrances.Add(entrance2);
				}
                else
                {
                    // if it is small, create one entrance in the middle 
                    var entrance = new Entrance(currentIdCounter++, clusterid1, clusterid2, y, ((i - 1) + entranceStart) / 2,
									  getNode(((i - 1) + entranceStart) / 2, y).NodeId,
									  getNode(((i - 1) + entranceStart) / 2, y + 1).NodeId, orientation);

					entrances.Add(entrance);
                }
            }

	        nextId = currentIdCounter;
			
			return entrances;
        }
        private void CreateEntranceEdges(Entrance entrance, AbsType type, Dictionary<int, AbsTilingNodeInfo> absNodes)
        {
            int level;
            switch (entrance.Orientation)
            {
                case Orientation.HORIZONTAL:
                    level = DetermineLevel(entrance.Coord1.Y);
                    break;
                case Orientation.VERTICAL:
                    level = DetermineLevel(entrance.Coord1.X);
                    break;
                default:
                    level = -1;
                    break;
            }

            var abstractNodeId1 = absNodes[entrance.Coord1Id].Id;
            var abstractNodeId2 = absNodes[entrance.Coord2Id].Id;

            switch (type)
            {
                case AbsType.ABSTRACT_TILE:
                case AbsType.ABSTRACT_OCTILE_UNICOST:
                    // Inter-edges: cost 1
                    var absTilingEdgeInfo1 = new AbsTilingEdgeInfo(Constants.COST_ONE, level, true);
                    var absTilingEdgeInfo2 = new AbsTilingEdgeInfo(Constants.COST_ONE, level, true);
                    HierarchicalMap.AbstractGraph.AddEdge(abstractNodeId1, abstractNodeId2, absTilingEdgeInfo1);
                    HierarchicalMap.AbstractGraph.AddEdge(abstractNodeId2, abstractNodeId1, absTilingEdgeInfo2);
                    break;
                case AbsType.ABSTRACT_OCTILE:
                    {
                        int unitCost;
                        switch (entrance.Orientation)
                        {
                            case Orientation.HORIZONTAL:
                            case Orientation.VERTICAL:
                                unitCost = Constants.COST_ONE;
                                break;
                            case Orientation.HDIAG2:
                            case Orientation.HDIAG1:
                            case Orientation.VDIAG1:
                            case Orientation.VDIAG2:
                                unitCost = (Constants.COST_ONE * 34) / 24;
                                break;
                            default:
                                unitCost = -1;
                                break;
                        }

                        var absTilingEdgeInfo3 = new AbsTilingEdgeInfo(unitCost, level, true);
                        var absTilingEdgeInfo4 = new AbsTilingEdgeInfo(unitCost, level, true);
                        HierarchicalMap.AbstractGraph.AddEdge(abstractNodeId1, abstractNodeId2, absTilingEdgeInfo3);
                        HierarchicalMap.AbstractGraph.AddEdge(abstractNodeId2, abstractNodeId1, absTilingEdgeInfo4);
                    }
                    break;
                default:
                    break;
            }
        }