/// <summary>
 /// Shifts the Min and Max Indices to the next set for route movement
 /// </summary>
 /// <param name="valueWaypoint">Value Waypoint interface to modify</param>
 /// <param name="scaleDirection">Direction of shift -1, 0, 1</param>
 public static void Shift(IValueWaypoint valueWaypoint, float scaleDirection)
 {
     if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD))
     {
         ValueSmoothWaypointUtils.ShiftMinMaxIndex(valueWaypoint, valueWaypoint.nodes.Length - 1, 0, ValueSmoothWaypointUtils._CanIncrement, _Add, 0.0f);
     }
     else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE))
     {
         ValueSmoothWaypointUtils.ShiftMinMaxIndex(valueWaypoint, 0, valueWaypoint.nodes.Length - 1, ValueSmoothWaypointUtils._CanDecrement, _Sub, 1.0f);
     }
     else // ValueSmoothWaypointUtils.DIRECTION_NONE
     {
     }
 }
        /// <summary>
        /// Initilizes a waypoint interface to start route
        /// </summary>
        /// <param name="valueWaypoint">Interface to initilize</param>
        /// <param name="onClamped">Callback for onClamped event, happens when each node is reached</param>
        public static void InitilizeDirection(IValueWaypoint valueWaypoint, EventHandler onClamped)
        {
            float scaleDirection = Mathf.Sign(valueWaypoint.scale);

            switch (valueWaypoint.actionType)
            {
            case ActionType.PingPong:
                if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD))
                {
                    valueWaypoint.currentIndex = 0;
                    valueWaypoint.minIndex     = 0;
                    valueWaypoint.maxIndex     = 1;
                    valueWaypoint.current      = 0.0f;
                }
                else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE))
                {
                    valueWaypoint.currentIndex = valueWaypoint.nodes.Length - 1;
                    valueWaypoint.minIndex     = valueWaypoint.nodes.Length - 1;
                    valueWaypoint.maxIndex     = 0;
                    valueWaypoint.current      = 1.0f;
                }
                break;

            case ActionType.Wrap:
                if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD))
                {
                    valueWaypoint.currentIndex = 0;
                    valueWaypoint.minIndex     = 0;
                    valueWaypoint.maxIndex     = valueWaypoint.minIndex + 1;
                    valueWaypoint.current      = 0.0f;
                }
                else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE))
                {
                    valueWaypoint.currentIndex = valueWaypoint.nodes.Length - 1;
                    valueWaypoint.minIndex     = valueWaypoint.nodes.Length - 1;
                    valueWaypoint.maxIndex     = 0;
                    valueWaypoint.current      = 1.0f;
                }
                break;

            case ActionType.None:
            case ActionType.Random:
            default:
                break;
            }
            valueWaypoint.onClamp += onClamped;
        }
        /// <summary>
        /// Shifts the Min and Max Indices to the next set for route movement
        /// </summary>
        /// <param name="valueWaypoint">Interface to modify</param>
        /// <param name="limit">Limit/End Index of movement for route section</param>
        /// <param name="begin">Route section begin Index</param>
        /// <param name="canChange">Test for can enter conditional change</param>
        /// <param name="doChange">Method to preform change</param>
        /// <param name="current">Value to set interfaces current value</param>
        internal static void ShiftMinMaxIndex(IValueWaypoint valueWaypoint, int limit, int begin, Func <int, int, bool> canChange, Func <int, int> doChange, float current)
        {
            valueWaypoint.minIndex = doChange.Invoke(valueWaypoint.minIndex);
            if (canChange.Invoke(valueWaypoint.minIndex, limit))
            {
                valueWaypoint.maxIndex = doChange.Invoke(valueWaypoint.minIndex);
            }
            else if (valueWaypoint.minIndex == limit)
            {
                valueWaypoint.maxIndex = begin;
            }
            else
            {
                valueWaypoint.minIndex = begin;
                valueWaypoint.maxIndex = doChange.Invoke(valueWaypoint.minIndex);
            }

            valueWaypoint.current = current;
        }
        /// <summary>
        /// Test current node position to determine end of route
        /// </summary>
        /// <param name="valueWaypoint">Value Waypoint to test for route complete</param>
        /// <returns>True is at end of route false if not</returns>
        public static bool IsRouteCycleCompleted(IValueWaypoint valueWaypoint)
        {
            float scaleDirection = Mathf.Sign(valueWaypoint.scale);

            if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD))
            {
                if (ValueSmoothWaypointUtils._GreaterOrEqual.Invoke(valueWaypoint, valueWaypoint.currentIndex))
                {
                    return(true);
                }
            }
            else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE))
            {
                if (ValueSmoothWaypointUtils._LessOrEqual.Invoke(valueWaypoint, valueWaypoint.currentIndex))
                {
                    return(true);
                }
            }
            return(false);
        }
        /// <summary>
        /// Responds to OnClamped event from Value Waypoint
        /// </summary>
        /// <param name="valueWaypoint">Value Waypoint sending the event</param>
        public static void OnValueWaypointClamp(IValueWaypoint valueWaypoint)
        {
            float scaleDirection = Mathf.Sign(valueWaypoint.scale);

            switch (valueWaypoint.actionType)
            {
            case ActionType.PingPong:
                if (!valueWaypoint.loop)
                {
                    if (!ValueSmoothWaypointUtils.IsRouteCycleCompleted(valueWaypoint))
                    {
                        ValueSmoothWaypointUtils.Shift(valueWaypoint, scaleDirection);
                    }
                }
                else
                {
                    if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE) && valueWaypoint.direction.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE))
                    {
                        if (!ValueSmoothWaypointUtils._FlipDirection.Invoke(valueWaypoint, valueWaypoint.currentIndex, ValueSmoothWaypointUtils._GreaterOrEqual))
                        {
                            ValueSmoothWaypointUtils.Shift(valueWaypoint, -scaleDirection);
                        }
                    }
                    else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE) && valueWaypoint.direction.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD))
                    {
                        if (!ValueSmoothWaypointUtils._FlipDirection.Invoke(valueWaypoint, valueWaypoint.currentIndex, ValueSmoothWaypointUtils._LessOrEqual))
                        {
                            ValueSmoothWaypointUtils.Shift(valueWaypoint, scaleDirection);
                        }
                    }
                    else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD) && valueWaypoint.direction.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD))
                    {
                        if (!ValueSmoothWaypointUtils._FlipDirection.Invoke(valueWaypoint, valueWaypoint.currentIndex, ValueSmoothWaypointUtils._GreaterOrEqual))
                        {
                            ValueSmoothWaypointUtils.Shift(valueWaypoint, scaleDirection);
                        }
                    }
                    else if (scaleDirection.Equals(ValueSmoothWaypointUtils.DIRECTION_FORWARD) && valueWaypoint.direction.Equals(ValueSmoothWaypointUtils.DIRECTION_REVERSE))
                    {
                        if (!ValueSmoothWaypointUtils._FlipDirection.Invoke(valueWaypoint, valueWaypoint.currentIndex, ValueSmoothWaypointUtils._LessOrEqual))
                        {
                            ValueSmoothWaypointUtils.Shift(valueWaypoint, -scaleDirection);
                        }
                    }
                }
                break;

            case ActionType.Wrap:
                if (!valueWaypoint.loop)
                {
                    if (!ValueSmoothWaypointUtils.IsRouteCycleCompleted(valueWaypoint))
                    {
                        ValueSmoothWaypointUtils.Shift(valueWaypoint, scaleDirection);
                    }
                }
                else
                {
                    ValueSmoothWaypointUtils.Shift(valueWaypoint, scaleDirection);
                }
                break;

            case ActionType.None:
            case ActionType.Random:
            default:
                break;
            }
            valueWaypoint.Prepare();
            ValueWaypointUtils.SetVecsToNode(valueWaypoint);
        }