public void init(BasicNavGraph para_bystanderGraph,
	                 List<int> para_cornerNodeIDs)
    {
        stateFactoryName = "RegularBystanderFactory";
        bystanderGraph = para_bystanderGraph;
        cornerNodeIDs = para_cornerNodeIDs;
        requestFlag_transToLinger = false;
    }
    public void init(BasicNavGraph para_bystanderGraph,
	                 Dictionary<string,List<int>> para_areaToNodes)
    {
        stateFactoryName = "LingerBystanderFactory";
        bystanderGraph = para_bystanderGraph;
        areaToNodes = para_areaToNodes;
        bystanderToArea = new Dictionary<string, string>();
        bystanderToAreaNodeIndex = new Dictionary<string, int>();
    }
    public void init(BasicNavGraph para_bystanderGraph,
	                 List<int> para_enterNodeList,
	                 List<int> para_cornerNodeIDs)
    {
        stateFactoryName = "EnterStateFactory";
        bystanderGraph = para_bystanderGraph;
        enterNodeList = para_enterNodeList;
        cornerNodeIDs = para_cornerNodeIDs;
        availabilityCounter = 0;
    }
    private void initBystanderNavGraph(Dictionary<string,Rect> para_worldBoundsLookup, Transform para_debugPrefab)
    {
        Dictionary<string,Rect> worldBoundsLookup = para_worldBoundsLookup;

        bystanderNavGraph = new BasicNavGraph();

        GameObject lwalkwayObj = GameObject.Find("LeftWalk");
        float graphZPos = lwalkwayObj.transform.position.z;
        Rect leftWalkwayWorld = worldBoundsLookup["LeftWalkway"];
        Vector3 lw_topMid = new Vector3(leftWalkwayWorld.x + (leftWalkwayWorld.width/2f),leftWalkwayWorld.y,graphZPos);
        Vector3 lw_botMid = new Vector3(lw_topMid.x,leftWalkwayWorld.y - (leftWalkwayWorld.height),graphZPos);

        Rect topWalkwayWorld = worldBoundsLookup["TopWalkway"];
        Vector3 tw_leftMid = new Vector3(topWalkwayWorld.x,topWalkwayWorld.y - (topWalkwayWorld.height/2f),graphZPos);
        Vector3 tw_rightMid = new Vector3(topWalkwayWorld.x + topWalkwayWorld.width,tw_leftMid.y,graphZPos);

        Rect rightWalkwayWorld = worldBoundsLookup["RightWalkway"];
        Vector3 rw_topMid = new Vector3(rightWalkwayWorld.x + (rightWalkwayWorld.width/2f),rightWalkwayWorld.y,graphZPos);
        Vector3 rw_botMid = new Vector3(rw_topMid.x,rightWalkwayWorld.y - rightWalkwayWorld.height,graphZPos);

        Rect bottomWalkwayWorld = worldBoundsLookup["BottomWalkway"];
        Rect bottomEntranceWorld = worldBoundsLookup["BottomEntrance"];
        List<Vector3> bottomWalkwayPoints = new List<Vector3>();
        List<Vector3> bottomEntrancePoints = new List<Vector3>();

        float entranceSpacing = 2;
        int numEntrances = (int) ((bottomEntranceWorld.width - entranceSpacing) / entranceSpacing);
        Vector3 nxtBottomWalkwayPt = new Vector3(bottomWalkwayWorld.x + entranceSpacing,bottomWalkwayWorld.y - (bottomWalkwayWorld.height/2f),graphZPos);
        Vector3 nxtBottomEntrancePt = new Vector3(bottomEntranceWorld.x + entranceSpacing,bottomEntranceWorld.y - ( Random.Range(0,2)),graphZPos);
        //Vector3 nxtBottomEntrancePt = new Vector3(bottomEntranceWorld.x + entranceSpacing,bottomEntranceWorld.y - (bottomEntranceWorld.height + Random.Range(2,6)),graphZPos);

        for(int i=0; i<numEntrances; i++)
        {
            bottomWalkwayPoints.Add(nxtBottomWalkwayPt);
            bottomEntrancePoints.Add(nxtBottomEntrancePt);

            nxtBottomWalkwayPt.x += entranceSpacing;
            nxtBottomEntrancePt.x += entranceSpacing;
            nxtBottomEntrancePt.y = bottomEntranceWorld.y - (bottomEntranceWorld.height + 1);//Random.Range(2,6));
        }

        Vector3[] posList = new Vector3[6] { lw_botMid, lw_topMid, tw_leftMid, tw_rightMid, rw_topMid, rw_botMid };
        int nodeTicketID = 0;
        for(int i=0; i<posList.Length; i++)
        {
            bystanderNavGraph.addNode(new WorldNode(nodeTicketID,1,posList[i]));
            if(i > 0) {	bystanderNavGraph.addEdge(nodeTicketID-1,nodeTicketID,new NavEdge(new int[2] { (nodeTicketID-1), nodeTicketID },1)); }
            nodeTicketID++;
        }
        cornerNodeIDs = new List<int>() { 0,2,4,5 };
        topNodes = new List<int>() { 2,3 };
        leftNodes = new List<int>() { 0,1 };
        rightNodes = new List<int>() { 4,5 };

        bottomWalkwayNodeIDs = new List<int>();
        for(int i=0; i<bottomWalkwayPoints.Count; i++)
        {
            bystanderNavGraph.addNode(new WorldNode(nodeTicketID,1,bottomWalkwayPoints[i]));
            bottomWalkwayNodeIDs.Add(nodeTicketID);
            if(i > 0) { bystanderNavGraph.addEdge(nodeTicketID-1,nodeTicketID,new NavEdge(new int[2] { (nodeTicketID-1), nodeTicketID },1)); }
            nodeTicketID++;
        }
        bystanderNavGraph.addEdge(bottomWalkwayNodeIDs[0],0,new NavEdge(new int[2] { bottomWalkwayNodeIDs[0], 0 },1));
        bystanderNavGraph.addEdge(bottomWalkwayNodeIDs[bottomWalkwayNodeIDs.Count-1],5,new NavEdge(new int[2] { bottomWalkwayNodeIDs[bottomWalkwayNodeIDs.Count-1], 5 },1));

        bottomEntranceNodeIDs = new List<int>();
        for(int i=0; i<bottomEntrancePoints.Count; i++)
        {
            bystanderNavGraph.addNode(new WorldNode(nodeTicketID,2,bottomEntrancePoints[i]));
            bottomEntranceNodeIDs.Add(nodeTicketID);
            bystanderNavGraph.addEdge(nodeTicketID,bottomWalkwayNodeIDs[i],new NavEdge(new int[2] { nodeTicketID, bottomWalkwayNodeIDs[i]},1));
            nodeTicketID++;
        }

        areas = new Dictionary<string, Rect>();
        areas.Add("L",leftWalkwayWorld);
        areas.Add("T",topWalkwayWorld);
        areas.Add("R",rightWalkwayWorld);

        GameObject navGraphRender = NavGraphUnityUtils.renderNavGraph("MPBystanderNavGraphRender",bystanderNavGraph,para_debugPrefab);
        navGraphRender.SetActive(false);
    }
    public void init(int[] para_mapSize,
	                 GridProperties para_gPropMapWorldBounds,
	                 BasicNavGraph para_worldNavGraph,
	                 ITerrainHandler para_terrainHandle,
	                 bool para_canWalk)
    {
        //mapSize = para_mapSize;
        gPropMapWorldBounds = para_gPropMapWorldBounds;
        worldNavGraph = para_worldNavGraph;
        terrainHandle = para_terrainHandle;

        currSpeed = walkSpeed;
        canWalk = para_canWalk;
    }
    private void initBlankNavGraph()
    {
        if(firstLevel)
        {
            // Create the datastructure.

            boardNavGraph = new BasicNavGraph();
            cellNameToNodeIDMap = new Dictionary<string,int>();
            nodeIDToCellNameMap = new Dictionary<int,string>();

            int boardWidth_inColumns = boardSize[0];
            int boardHeight_inRows = boardSize[1];

            int cellID = 0;
            GameObject hexBoardObj = GameObject.Find("HexBoard");
            for(int c=0; c<boardWidth_inColumns; c++)
            {

                int numOfRowsForColumn = boardHeight_inRows;

                bool isOddColumn = false;
                if((c%2) != 0)
                {
                    numOfRowsForColumn = boardHeight_inRows-1;
                    isOddColumn = true;
                }

                for(int r=0; r<numOfRowsForColumn; r++)
                {
                    Transform reqCell = hexBoardObj.transform.FindChild("Cell("+c+","+r+")");
                    if(reqCell != null)
                    {

                        WorldNode nwNavNode = new WorldNode(cellID,1,reqCell.position);
                        boardNavGraph.addNode(nwNavNode);
                        cellNameToNodeIDMap.Add(reqCell.name,cellID);
                        nodeIDToCellNameMap.Add(cellID,reqCell.name);

                        // Get potential neighbours.
                        List<int[]> potentialNeighbourCoords = new List<int[]>();
                        potentialNeighbourCoords.Add(new int[2] {c,r-1});
                        potentialNeighbourCoords.Add(new int[2] {c,r+1});

                        if(! isOddColumn)
                        {
                            potentialNeighbourCoords.Add(new int[2] {c-1,r-1});
                            potentialNeighbourCoords.Add(new int[2] {c-1,r});

                            //potentialNeighbourCoords.Add(new int[2] {c+1,r-1});
                            //potentialNeighbourCoords.Add(new int[2] {c+1,r});
                        }
                        else
                        {
                            potentialNeighbourCoords.Add(new int[2] {c-1,r});
                            potentialNeighbourCoords.Add(new int[2] {c-1,r+1});

                            //potentialNeighbourCoords.Add(new int[2] {c+1,r});
                            //potentialNeighbourCoords.Add(new int[2] {c+1,r+1});
                        }

                        for(int i=0; i<potentialNeighbourCoords.Count; i++)
                        {
                            int[] tmpCoords = potentialNeighbourCoords[i];
                            string potentialNeighbourName = "Cell("+tmpCoords[0]+","+tmpCoords[1]+")";

                            Transform reqNeighbourCell = hexBoardObj.transform.FindChild(potentialNeighbourName);
                            if(reqNeighbourCell != null)
                            {
                                if(cellNameToNodeIDMap.ContainsKey(potentialNeighbourName))
                                {
                                    int neighbourNodeID = cellNameToNodeIDMap[potentialNeighbourName];
                                    boardNavGraph.addEdge(cellID,neighbourNodeID,new NavEdge(new int[2] {cellID,neighbourNodeID},1));
                                }
                            }
                        }

                        cellID++;
                    }
                }
            }

            GameObject navRendering = NavGraphUnityUtils.renderNavGraph("MPBoardNavGraphRender",boardNavGraph,debugPrefab);
            navRendering.SetActive(false);

        }
        else
        {
            // If not first level. Simply reset all node types to type 1: i.e. reachable type.

            List<int> nodeKeys = boardNavGraph.getAllNodeKeys();
            for(int i=0; i<nodeKeys.Count; i++)
            {
                boardNavGraph.setNodeType(nodeKeys[i],1);
            }
        }
    }
    // Nodes are added by moving a single cell.
    // Edges are initially one length edges.
    // Post processing can reduce the number of nodes.
    //
    //        # # #
    //        # X #
    //        # # #
    //
    // X = Node checking.
    // # = Neighbour/Graph Edge checking.
    //
    public NavGraph constructGraph()
    {
        BasicNavGraph retGraph = new BasicNavGraph();

        int nxtNodeID = 0;
        int nxtEdgeID = 0;
        Dictionary<string,int> coordToNodeIDMap = new Dictionary<string,int>();

        Texture2D mapImg = Resources.Load<Texture2D>(imgPath);
        if(mapImg != null)
        {
            Color[] pixels = mapImg.GetPixels();

            for(int r=0; r<mapImg.height; r++)
            {
                for(int c=0; c<mapImg.width; c++)
                {
                    Color tmpPixel = pixels[(r * mapImg.width) + c];

                    if(tmpPixel.Equals(traversibleColor))
                    {
                        // Add new node.
                        ImgNode nwNode = new ImgNode(nxtNodeID,1,new int[2] { c,r });
                        retGraph.addNode(nwNode);
                        coordToNodeIDMap.Add((""+c+"-"+r),nwNode.getNodeID());
                        nxtEdgeID++;

                        // Get valid neighbourhood pixels.
                        List<Color> neighbourhoodPixels = new List<Color>();
                        List<int[]> reqNPixCoords = new List<int[]>();
                        reqNPixCoords.Add(new int[2]{(c-1),(r-1)});
                        reqNPixCoords.Add(new int[2]{(c),(r-1)});
                        reqNPixCoords.Add(new int[2]{(c+1),(r-1)});
                        reqNPixCoords.Add(new int[2]{(c-1),(r)});
                        List<int> validCoordIndexList = new List<int>();
                        for(int k=0; k<reqNPixCoords.Count; k++)
                        {
                            int[] tmpCoords = reqNPixCoords[k];

                            if((tmpCoords[0] >= 0)&&(tmpCoords[0] < mapImg.width)
                             &&(tmpCoords[1] >= 0)&&(tmpCoords[1] < mapImg.height))
                            {
                                // Valid coords.
                                validCoordIndexList.Add(k);
                                neighbourhoodPixels.Add( pixels[(tmpCoords[1] * mapImg.width) + tmpCoords[0]] );
                            }
                        }

                        // Check for neighbours and create edges. (NavGraph will handle the internal creation of neighbour references, just run addEdge).
                        for(int k=0; k<validCoordIndexList.Count; k++)
                        {
                            if(neighbourhoodPixels[k].Equals(traversibleColor))
                            {
                                int[] neighbourCoords = reqNPixCoords[k];
                                int neighbourID = coordToNodeIDMap[(""+neighbourCoords[0]+"-"+neighbourCoords[1])];

                                retGraph.addEdge(nwNode.getNodeID(),neighbourID,new NavEdge(new int[2] {nwNode.getNodeID(),neighbourID},1));
                            }
                        }
                    }
                }
            }
        }

        return retGraph;
    }
    // Nodes are added by moving a single cell.
    // Edges are initially one length edges.
    // Post processing can reduce the number of nodes.
    //
    //        # # #
    //        # X #
    //        # # #
    //
    // X = Node checking.
    // # = Neighbour/Graph Edge checking.
    //
    public NavGraph constructGraph()
    {
        BasicNavGraph retGraph = new BasicNavGraph();

        int nxtNodeID = 0;
        //int nxtEdgeID = 0;
        Dictionary<string,int> coordToNodeIDMap = new Dictionary<string,int>();

        Texture2D mapImg = Resources.Load<Texture2D>(imgPath);
        if(mapImg != null)
        {
            // NOTE: UNITY RETURNS THIS ARRAY WHICH STARTS WITH ROWS BOTTOM-UP.
            pixels = mapImg.GetPixels();

            for(int r=0; r<mapImg.height; r++)
            {
                for(int c=0; c<mapImg.width; c++)
                {
                    // (pixels.Length-mapImg.width) - This is to navigate the image top down while still abiding with Unity's returned pixel array which goes bottom up.
                    Color tmpPixel = pixels[(pixels.Length - mapImg.width) - (r * mapImg.width) + c];

                    if(tmpPixel.Equals(traversibleColor))
                    {
                        // Add new node.
                        WorldNode nwNode = new WorldNode(nxtNodeID,1, new Vector3((worldGProp.x + (worldGProp.cellWidth/2f)) + (worldGProp.cellWidth * c),
                                                                                  (worldGProp.y - (worldGProp.cellWidth/2f)) - (worldGProp.cellHeight * r),
                                                                                  worldGProp.z));

                        retGraph.addNode(nwNode);
                        coordToNodeIDMap.Add((""+c+"-"+r),nwNode.getNodeID());
                        nxtNodeID++;

                        // Get valid neighbourhood pixels.
                        List<Color> neighbourhoodPixels = new List<Color>();
                        List<int[]> reqNPixCoords = new List<int[]>();

                        //reqNPixCoords.Add(new int[2]{(c-1),(r-1)});
                        reqNPixCoords.Add(new int[2]{(c),(r-1)});
                        //reqNPixCoords.Add(new int[2]{(c+1),(r-1)});
                        reqNPixCoords.Add(new int[2]{(c-1),(r)});
                        List<int> validCoordIndexList = new List<int>();
                        for(int k=0; k<reqNPixCoords.Count; k++)
                        {
                            int[] tmpCoords = reqNPixCoords[k];

                            if((tmpCoords[0] >= 0)&&(tmpCoords[0] < mapImg.width)
                               &&(tmpCoords[1] >= 0)&&(tmpCoords[1] < mapImg.height))
                            {
                                // Valid coords.
                                validCoordIndexList.Add(k);
                                neighbourhoodPixels.Add( pixels[(pixels.Length - mapImg.width) - (tmpCoords[1] * mapImg.width) + tmpCoords[0]] );
                            }
                        }

                        // Check for neighbours and create edges. (NavGraph will handle the internal creation of neighbour references, just run addEdge).
                        for(int k=0; k<validCoordIndexList.Count; k++)
                        {
                            if(neighbourhoodPixels[k].Equals(traversibleColor))
                            {
                                int[] neighbourCoords = reqNPixCoords[k];
                                int neighbourID = coordToNodeIDMap[(""+neighbourCoords[0]+"-"+neighbourCoords[1])];

                                retGraph.addEdge(nwNode.getNodeID(),neighbourID,new NavEdge(new int[2] {nwNode.getNodeID(),neighbourID},1));
                            }
                        }
                    }
                }
            }
        }

        return retGraph;
    }