/// <summary>
    /// Go through all of the generated rooms that match the parameter and add a small room to them so they don't lead to nowhere.
    /// </summary>
    /// <param name="typeToCloseOff">The room type to look for.</param>
    private void CloseOffPaths()
    {
        if (closeOffParent == null)
        {
            closeOffParent = new GameObject("Path closing rooms - ");
            closeOffParent.transform.parent = emptyGameObject.transform;
        }

        foreach (var roomType in RoomTypesToCloseOff)
        {
            foreach (GameObject go in GameObject.FindGameObjectsWithTag("RoomInstance"))
            {
                currRoom = go.GetComponent <Room>();
                if (currRoom.GetRoomType().Equals(roomType))
                {
                    foreach (var exit in currRoom.GetRoomExits())
                    {
                        if (exit.GetConnectionStatus().Equals(RoomExit.ExitStatus.Connected)) //if exit is connected, skip it
                        {
                            continue;
                        }

                        Room newRoom = (Room)Instantiate(rnd.GetRandom(RoomsToUseToClosePath));
                        newRoom.SetupCollider();
                        currExit = exit.GetExit();
                        var newRoomExits = newRoom.GetExits();
                        var exitToMatch  = rnd.GetRandom(newRoomExits);
                        newRoom.tag = "RoomInstance";
                        newRoom.gameObject.layer = LayerMask.NameToLayer("RoomInstances");

                        currExit.MatchExits(exitToMatch);

                        if (collision.DetectCollision(newRoom))
                        {
                            MarkRoomForDestruction(newRoom);
                            currRoom.CloseCollidingExit(currExit); // cannot add room here so close the exit
                            continue;
                        }
                        currRoom.ConnectExits(currExit, exitToMatch);
                        newRoom.ConnectExits(exitToMatch, currExit);

                        newRoom.transform.SetParent(closeOffParent.transform);
                    }
                }
            }
        }
        closeOffParent.name += closeOffParent.GetComponentsInChildren <Room>().Count();
    }
    /// <summary>
    /// Try and add the specified 'ExitRoom' to one of the open exits.
    /// </summary>
    private void SetupExitRoom()
    {
        if (ExitRoom == null) //no exit room prefab was provided
        {
            hasExitRoomBeenSuccessfullyAdded = true;
            if (_DEBUG_MODE)
            {
                FileLogger.Log(">No Exit Room Specified. Terminating SetupExitRoom function.<");
            }
            return;
        }

        if (_DEBUG_MODE)
        {
            FileLogger.Log(">Starting SetupExitRoom...");
        }

        if ((supportFunctions.GetAllRoomsWithActiveExits().Count < 3 || supportFunctions.GetRoomsWithPossibleExits().Count < 5) && expandPathBy > 1)
        {
            //Make sure there are enough exits before spawning an exit room as it would certainly be a dead end
            if (_DEBUG_MODE)
            {
                FileLogger.Log("Postponing SetupExitRoom due to possibility of creating a dead-end.");
            }
            hasExitRoomBeenSuccessfullyAdded = false;
            return;
        }

        //Select a room to connect the exit to.
        int excludeRooms = 0; //counter to keep track of how many rooms we've backtracked so we do not check the same ones again

        currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits(GetComponent <ConnectionRules>().GetPossibleConnectionBetweenRoomsByRoomType(ExitRoom.GetRoomType()),
                                                                       ref excludeRooms);; //find a room to add the exit to(needs to meet one of the connection rules criteria)

        if (currRoom.Equals(InitialRoom))
        {
            if (_DEBUG_MODE)
            {
                FileLogger.Log(">Attempted to connect exit room to initial room. Returning and awaiting more available rooms.<");
            }

            hasExitRoomBeenSuccessfullyAdded = true;
            return;
        }

        if (currRoom == null)
        {
            //force stop the execution of the function if a suitable room wasn't found
            if (_DEBUG_MODE)
            {
                FileLogger.Log(">!< Could not add exit room to any of the rooms. Terminating SetupExitRoom function! >!<");
            }

            hasExitRoomBeenSuccessfullyAdded = false;
            return;
        }

        Room exitRoom = (Room)Instantiate(ExitRoom);

        exitRoom.SetupCollider();
        exitRoom.tag = "RoomInstance";
        exitRoom.gameObject.layer = LayerMask.NameToLayer("RoomInstances");
        var           exitRoomExits     = exitRoom.GetExits(); //get exits for the new room
        RoomConnector exitToMatch       = null;
        bool          collisionDetected = false;

        do
        {
            if (currRoom == null || currRoom.Equals(InitialRoom))
            {
                //force stop the execution of the function if a suitable room wasn't found
                if (_DEBUG_MODE)
                {
                    FileLogger.Log(">!< Could not add exit room to any of the rooms. Terminating SetupExitRoom function! >!<");
                }

                MarkRoomForDestruction(exitRoom);
                hasExitRoomBeenSuccessfullyAdded = false;
                return;
            }

            currExit = rnd.GetRandom(currRoom.GetActiveExits());

            if (collisionDetected)
            {
                currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits(GetComponent <ConnectionRules>().GetPossibleConnectionBetweenRoomsByRoomType(exitRoom.GetRoomType()),
                                                                               ref excludeRooms); //find a room to add the exit to
                excludeRooms++;                                                                   //if this room cannot be connected to the one that was just found, then ignore it next time as we don't close the exit / prevent inf loop
                continue;
            }

            exitToMatch = rnd.GetRandom(exitRoomExits);                   //select default exit or choose one at random
            currExit.MatchExits(exitToMatch);                             //rotate the new room so it connects correctly
        }while (collisionDetected = collision.DetectCollision(exitRoom)); //deal with the collision

        currRoom.ConnectExits(currExit, exitToMatch);
        exitRoom.ConnectExits(exitToMatch, currExit);

        exitRoom.transform.parent        = emptyGameObject.transform;
        exitRoom.name                    = "ExitRoom";
        hasExitRoomBeenSuccessfullyAdded = true;
        if (markEndRoom)
        {
            exitRoom.GetComponent <Renderer>().material.color = Color.red;
        }

        if (_DEBUG_MODE)
        {
            FileLogger.Log("<SetupExitRoom was successful.");
        }
    }
    /// <summary>
    /// Instantiates a room and adds it to the level. Based on the passed in argument it will either
    /// add a room to the main path of the level(true) or to a random room(false).
    /// Returns 1 if function was successful. 0 if collision occured. -1 if there are no more active exits.
    /// </summary>
    /// <param name="onMainPath">True: generate the main path. False: expand the level</param>
    /// <returns>-1 if dead end has been found; 0 if a collision has occured; 1 if room was generated successfully.</returns>
    private int GenerateRoom(bool onMainPath = true)
    {
        if (supportFunctions.GetTotalNumberOfActiveExits() == 0)
        {
            return(-1);
        }

        //try and add the exit room if the previous attempt was unsuccessful
        if (!onMainPath && supportFunctions.GetAllRoomsWithActiveExits().Count > 3 && !hasExitRoomBeenSuccessfullyAdded && CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS == 0)
        {//dont generate during main path generation, but also make sure the function is not trying to add another room at this time
            if (_DEBUG_MODE)
            {
                FileLogger.Log(">!< Trying SetupExitRoom during Expansion >!<");
            }
            SetupExitRoom();
        }

        //if expanding level( NOT onMainPath) and not re-trying due to collision ( curr unsuccessful attempts is 0)
        if (!onMainPath && CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS == 0)
        {
            currRoom = rnd.GetRandom(supportFunctions.GetAllRoomsWithActiveExits().ToArray()); //pick a random open exit from the list to use
        }
        //if we're not trying to replace a room due to collision, get a new random exit
        if (CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS == 0)
        {
            currExit = rnd.GetRandom(currRoom.GetActiveExits()); //get the exit's room component
        }
        var possibleRoomConnections = GetComponent <ConnectionRules>().GetPossibleConnectionBetweenRoomsByRoomType(currExit.transform.parent.GetComponent <Room>().GetRoomType());
        var pickRandomRoomType      = rnd.GetRandom(possibleRoomConnections);             //pick randomly a room type which can be connected to the current one's exit
        var newRoomPrefab           = rnd.GetRandomByRoomType(Rooms, pickRandomRoomType); //find item with specific room type

        if (onMainPath)
        {
            //avoid dead end if the new room will have only 1 exit which will be closed upon conneciton with the current room, or if there are few exits left
            if (newRoomPrefab.GetExits().Length <= 1 || supportFunctions.GetTotalNumberOfActiveExits() <= 3)
            {
                supportFunctions.AvoidDeadEnd(ref newRoomPrefab, possibleRoomConnections);
            }
        }
        else
        {
            if (supportFunctions.GetTotalNumberOfActiveExits() <= 5)
            {
                supportFunctions.AvoidDeadEnd(ref newRoomPrefab, possibleRoomConnections);
            }
        }

        var newRoom = (Room)Instantiate(newRoomPrefab);

        if (onMainPath)
        {
            newRoom.name += "SP" + uniqueID;
        }
        else
        {
            newRoom.name += "EXP" + uniqueID;
        }


        newRoom.SetupCollider();
        newRoom.tag = "RoomInstance";
        newRoom.gameObject.layer = LayerMask.NameToLayer("RoomInstances");

        var newRoomExits = newRoom.GetExits();          //get exits for the new room
        var exitToMatch  = rnd.GetRandom(newRoomExits); //select default exit or choose one at random

        currExit.MatchExits(exitToMatch);               //rotate the new room so it connects correctly

        if (collision.DetectCollision(newRoom))         //deal with the collision
        {
            MarkRoomForDestruction(newRoom);
            CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS++;

            if (CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS >= MAX_UNSUCCESSFUL_ROOM_REPLACEMENT_ATTEMPTS) //close off exit and backtrack
            {
                //close off exit only if there are other exits still open - otherwise it would lead to a complete dead end
                CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS = 0;
                currRoom.CloseCollidingExit(currExit);

                //find a new room with active exits.
                if (onMainPath)
                {
                    currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits();
                }

                //else case will be executed next time the function is called as currRoom will be randomly picked if not onMainPath
            }

            return(0);
        }
        //reset attempts and connect the rooms
        CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS = 0;
        currRoom.ConnectExits(currExit, exitToMatch);
        newRoom.ConnectExits(exitToMatch, currExit);

        if (allowLoops)
        {
            newRoom.ConnectActiveExitsInProximity();
        }

        if (onMainPath)
        {
            newRoom.transform.SetParent(spParent.transform);
            if (highlightMainPath)
            {
                // "highlight" the main path
                currRoom.GetComponent <Renderer>().material.color = Color.green;
                newRoom.GetComponent <Renderer>().material.color  = Color.green;
            }

            //if the new room doesn't have an exit, don't move into it
            if (newRoom.GetActiveExits().Length >= 1)
            {
                currRoom = newRoom;
            }

            if (currRoom.GetActiveExits().Length == 0)
            {
                currRoom = supportFunctions.BacktrackToLastRoomWithActiveExits();
                CURRENT_UNSUCCESSFUL_ROOM_REPLACMENT_ATTEMPTS = 0;
            }
        }
        else
        {
            newRoom.transform.SetParent(expParent.transform);
        }
        uniqueID++;

        return(1);
    }