/// <summary>
 /// Add a new cell to the layout that correspond to a certain node in the mission graph
 /// </summary>
 /// <param name="node">corresponding node in the mission graph</param>
 /// <param name="parentID">the id of the parent that the new cell should be connected to</param>
 /// <returns>True if it succeed and False otherwise</returns>
 public bool addCell(MissionGraph.Node node, int parentID)
 {
     if (node.type == MissionGraph.NodeType.Lock)
     {
         OpenNode selected = this.getWorkingLocation(parentID, node.accessLevel - 1);
         if (selected == null)
         {
             return(false);
         }
         Cell newCell = new Cell(selected.x, selected.y, CellType.Normal, node);
         newCell.connectCells(selected.parent, DoorType.KeyLock);
         newCell.parent = selected.parent;
         this.addNewNode(newCell, node.accessLevel, node.id);
     }
     else if (node.type == MissionGraph.NodeType.Puzzle)
     {
         OpenNode selected = this.getWorkingLocation(parentID, node.accessLevel);
         if (selected == null)
         {
             return(false);
         }
         Cell newCell = new Cell(selected.x, selected.y, CellType.Normal, node);
         newCell.connectCells(selected.parent, DoorType.Open);
         newCell.parent = selected.parent;
         this.addNewNode(newCell, node.accessLevel + 1, node.id);
     }
     else if (node.type == MissionGraph.NodeType.Lever)
     {
         OpenNode selected = this.getWorkingLocation(parentID, node.accessLevel);
         if (selected == null)
         {
             return(false);
         }
         Cell newCell = new Cell(selected.x, selected.y, CellType.Normal, node);
         newCell.connectCells(selected.parent, DoorType.Open);
         newCell.parent = selected.parent;
         this.usedSpaces.Add(newCell.getLocationString(), newCell);
     }
     else
     {
         OpenNode selected = this.getWorkingLocation(parentID, node.accessLevel);
         if (selected == null)
         {
             return(false);
         }
         Cell newCell = new Cell(selected.x, selected.y, CellType.Normal, node);
         if (selected.parent.node.type == MissionGraph.NodeType.Puzzle)
         {
             newCell.connectCells(selected.parent, DoorType.PuzzleLock);
         }
         else if (selected.parent.node.type == MissionGraph.NodeType.Lever)
         {
             newCell.connectCells(selected.parent, DoorType.LeverLock);
         }
         else
         {
             newCell.connectCells(selected.parent, DoorType.Open);
         }
         if (node.getChildren().Count == 0)
         {
             this.usedSpaces.Add(newCell.getLocationString(), newCell);
         }
         else
         {
             this.addNewNode(newCell, node.accessLevel, parentID);
         }
         newCell.parent = selected.parent;
     }
     return(true);
 }
        /// <summary>
        /// Generate a map layout that correspond to the input mission graph
        /// </summary>
        /// <param name="graph">the mission graph that need to be mapped to a 2D layout</param>
        /// <returns>a 2D layout of the mission graph</returns>
        public Map generateDungeon(MissionGraph.Graph graph)
        {
            Map result = new Map(this.random);

            result.initializeCell(graph.nodes[0]);
            #region  make initial dungeon
            List <MissionGraph.Node>            open      = new List <MissionGraph.Node>();
            Dictionary <MissionGraph.Node, int> parentIDs = new Dictionary <MissionGraph.Node, int>();
            foreach (MissionGraph.Node child in graph.nodes[0].getChildren())
            {
                open.Add(child);
                parentIDs.Add(child, 0);
            }
            HashSet <MissionGraph.Node> nodes = new HashSet <MissionGraph.Node>();
            nodes.Add(graph.nodes[0]);
            while (open.Count > 0)
            {
                MissionGraph.Node current = open[0];
                open.RemoveAt(0);
                if (nodes.Contains(current))
                {
                    continue;
                }
                nodes.Add(current);
                if (!result.addCell(current, parentIDs[current]))
                {
                    return(null);
                }
                foreach (MissionGraph.Node child in current.getChildren())
                {
                    if (!parentIDs.ContainsKey(child))
                    {
                        if (current.type == MissionGraph.NodeType.Lock ||
                            current.type == MissionGraph.NodeType.Puzzle)
                        {
                            parentIDs.Add(child, current.id);
                        }
                        else
                        {
                            parentIDs.Add(child, parentIDs[current]);
                        }
                    }
                    open.Add(child);
                }
            }
            #endregion

            #region make lever connections
            open.Clear();
            nodes.Clear();
            open.Add(graph.nodes[0]);
            while (open.Count > 0)
            {
                MissionGraph.Node current = open[0];
                open.RemoveAt(0);
                if (nodes.Contains(current))
                {
                    continue;
                }
                nodes.Add(current);
                foreach (MissionGraph.Node child in current.getChildren())
                {
                    Cell from = result.getCell(current.id);
                    Cell to   = result.getCell(child.id);
                    if (current.type == MissionGraph.NodeType.Lever)
                    {
                        if (!result.makeConnection(from, to, nodes.Count * nodes.Count))
                        {
                            return(null);
                        }
                    }
                    open.Add(child);
                }
            }
            #endregion
            return(result);
        }