/// Finds shortest path between Nodes.
        /// Once the path is found, it will return the path as List of Positions ( not Nodes, but vector3. If you need Nodes, use FindShortestPathOfNodes).
        /// <returns> Returns list of **Positions**</returns>
        /// <param name="startNodeID">Find the path from this node</param>
        /// <param name="endNodeID">Find the path to this node</param>
        /// <param name="pathType">Path type. It can be a straight line or curved path</param>
        /// <param name="executionType">Synchronous is immediate and locks the control till path is found and returns the path.
        /// Asynchronous type runs in coroutines with out locking the control. If you have more than 50 Nodes, Asynchronous is recommended</param>
        /// <param name="searchMode"> This is still WIP. For now, Intermediate and Complex does a tad bit more calculations to make the path even shorter</param>
        /// <param name="OnPathFound">Callback once the path is found</param>


        public static void FindShortestPathOfPoints(this PathFinder manager, Vector3 startPoint, Vector3 endPoint, PathLineType pathType, Execution executionType, SearchMode searchMode, System.Action <List <Vector3> > OnPathFound)
        {
            PathFollowerUtility.FindShortestPathOfPoints_Internal(manager, startPoint, endPoint, pathType, executionType, searchMode, OnPathFound);
        }
        internal static void FindShortestPathOfPoints_Internal(PathFinder manager, Vector3 startPoint, Vector3 endPoint, PathLineType pathType, Execution execution, SearchMode searchMode, System.Action <List <Vector3> > OnPathFound)
        {
            bool makeItMoreAccurate    = searchMode == SearchMode.Intermediate || searchMode == SearchMode.Complex;
            int  nearestPointFromStart = manager.FindNearestNode(startPoint);
            int  nearestPointFromEnd   = -1;

            if (nearestPointFromStart != -1)
            {
                nearestPointFromEnd = manager.FindNearestNode(endPoint);
            }

            if (QPathFinder.Logger.CanLogInfo)
            {
                QPathFinder.Logger.LogInfo("Nearest point from start" + startPoint + " is " + nearestPointFromStart, true);
            }
            if (QPathFinder.Logger.CanLogInfo)
            {
                QPathFinder.Logger.LogInfo("Nearest point from end:" + endPoint + " is " + nearestPointFromEnd, true);
            }

            if (nearestPointFromEnd == -1 || nearestPointFromStart == -1)
            {
                if (QPathFinder.Logger.CanLogError)
                {
                    QPathFinder.Logger.LogError("Could not find path between " + nearestPointFromStart + " and " + nearestPointFromEnd, true);
                }
                OnPathFound(null);
                return;
            }

            float startTime = Time.realtimeSinceStartup;


            System.Action <List <Node> > onPathOfNodesFound = delegate(List <Node> nodes)
            {
                if (nodes == null || nodes.Count == 0)
                {
                    OnPathFound(null);
                    return;
                }

                List <System.Object> allNodes = new List <System.Object>();
                if (nodes != null)
                {
                    foreach (var a in nodes)
                    {
                        allNodes.Add(a);
                    }
                }

                if (QPathFinder.Logger.CanLogInfo)
                {
                    QPathFinder.Logger.LogInfo("Search Mode " + searchMode.ToString() + " opted", true);
                }

                if (makeItMoreAccurate)
                {
                    if (allNodes.Count > 1)
                    {
                        Vector3 shortestPointOnPath;
                        int     nearestNode    = -1;
                        Path    currentPath    = null;
                        int     shortestPathID = -1;


                        {
                            nearestNode    = ((Node)allNodes[0]).autoGeneratedID;
                            shortestPathID = -1;
                            currentPath    = manager.graphData.GetPathBetween(GetNodeFromNodeOrVector(allNodes, 0), GetNodeFromNodeOrVector(allNodes, 1));

                            if (currentPath != null)
                            {
                                shortestPointOnPath = GetClosestPointOnAnyPath(nearestNode, manager, startPoint, out shortestPathID);

                                if (shortestPathID == currentPath.autoGeneratedID)
                                {
                                    allNodes[0] = shortestPointOnPath;
                                }
                                else
                                {
                                    allNodes.Insert(0, shortestPointOnPath);
                                }
                            }
                            else
                            {
                                if (QPathFinder.Logger.CanLogError)
                                {
                                    QPathFinder.Logger.LogInfo("Error occured while finding path");
                                }
                            }
                        }

                        {
                            shortestPathID = -1;
                            nearestNode    = ((Node)allNodes[allNodes.Count - 1]).autoGeneratedID;
                            currentPath    = manager.graphData.GetPathBetween(GetNodeFromNodeOrVector(allNodes, allNodes.Count - 2), GetNodeFromNodeOrVector(allNodes, allNodes.Count - 1));

                            if (currentPath != null)
                            {
                                shortestPointOnPath = GetClosestPointOnAnyPath(nearestNode, manager, endPoint, out shortestPathID);

                                if (shortestPathID == currentPath.autoGeneratedID)
                                {
                                    allNodes[allNodes.Count - 1] = shortestPointOnPath;
                                }
                                else
                                {
                                    allNodes.Add(shortestPointOnPath);
                                }
                            }
                            else
                            {
                                if (QPathFinder.Logger.CanLogError)
                                {
                                    QPathFinder.Logger.LogInfo("Error occured while finding path");
                                }
                            }
                        }
                    }
                    else
                    {
                        if (QPathFinder.Logger.CanLogWarning)
                        {
                            QPathFinder.Logger.LogWarning("Unable to get the best result due to less node count", true);
                        }
                    }
                }

                List <Vector3> path = null;

                {
                    allNodes.Insert(0, startPoint);
                    allNodes.Add(endPoint);

                    path = (pathType == PathLineType.Straight ? GetStraightPathPoints(allNodes) : GetCatmullRomCurvePathPoints(allNodes));
                }

                if (QPathFinder.Logger.CanLogInfo)
                {
                    for (int i = 1; i < path.Count; i++)
                    {
                        Debug.DrawLine(path[i - 1], path[i], Color.red, QPathFinder.Logger.DrawLineDuration);
                    }
                }

                OnPathFound(path);
            };

            manager.FindShortestPathOfNodes(nearestPointFromStart, nearestPointFromEnd, execution, onPathOfNodesFound);
        }
        /// Finds shortest path between Nodes.
        /// Once the path is found, it will return the path as List of Positions (not Nodes, but vector3. If you need Nodes, use FindShortestPathOfNodes).
        /// <returns> Returns list of **Positions**</returns>
        /// <param name="startNodeID">Find the path from this node</param>
        /// <param name="endNodeID">Find the path to this node</param>
        /// <param name="pathType">Path type. It can be a straight line or curved path</param>
        /// <param name="executionType">Synchronous is immediate and locks the control till path is found and returns the path.
        /// Asynchronous type runs in coroutines without locking the control. If you have more than 50 Nodes, Asynchronous is recommended</param>
        /// <param name="OnPathFound">Callback once the path is found</param>

        public static void FindShortestPathOfPoints(this PathFinder manager, int startNodeID, int endNodeID, PathLineType pathType, Execution executionType, System.Action <List <Vector3> > OnPathFound)
        {
            PathFollowerUtility.FindShortestPathOfPoints_Internal(manager, startNodeID, endNodeID, pathType, executionType, OnPathFound);
        }
        //
        // *** PRIVATE AND INTERNAL ***

        #region PRIVATE AND INTERNAL

        internal static void FindShortestPathOfPoints_Internal(PathFinder manager, int startNodeID, int endNodeID, PathLineType pathType, Execution execution, System.Action <List <Vector3> > OnPathFound)
        {
            int nearestPointFromStart = startNodeID;
            int nearestPointFromEnd   = endNodeID;


            if (nearestPointFromEnd == -1 || nearestPointFromStart == -1)
            {
                if (QPathFinder.Logger.CanLogError)
                {
                    QPathFinder.Logger.LogError("Could not find path between " + nearestPointFromStart + " and " + nearestPointFromEnd, true);
                }
                OnPathFound(null);
                return;
            }

            float startTime = Time.realtimeSinceStartup;

            System.Action <List <Node> > onPathOfNodesFound = delegate(List <Node> nodes)
            {
                if (nodes == null || nodes.Count == 0)
                {
                    OnPathFound(null);
                }

                List <System.Object> allNodes = new List <System.Object>();
                List <Vector3>       path     = null;

                if (nodes != null)
                {
                    foreach (var a in nodes)
                    {
                        allNodes.Add(a.Position);
                    }
                }
                path = (pathType == PathLineType.Straight ? GetStraightPathPoints(allNodes) : GetCatmullRomCurvePathPoints(allNodes));

                if (QPathFinder.Logger.CanLogInfo)
                {
                    for (int i = 1; i < path.Count; i++)
                    {
                        Debug.DrawLine(path[i - 1], path[i], Color.red, QPathFinder.Logger.DrawLineDuration);
                    }
                }

                OnPathFound(path);
            };

            manager.FindShortestPathOfNodes(nearestPointFromStart, nearestPointFromEnd, execution, onPathOfNodesFound);
        }