private Instruction CreateInstructionFor(object target, string velocityMemberName,
                                                 object valueBefore, object valueAfter, double timeBetween, double instructionTime,
                                                 Type typeOfTarget, Type typeOfValue)
        {
            Type type = typeof(Instruction <,>).MakeGenericType(typeOfTarget, typeOfValue);

            object[] arguments = null;

            if (typeOfValue == typeof(float))
            {
                float difference = (float)valueAfter - (float)valueBefore;

                if (InstructionManager.IsRotationMember(InstructionManager.GetStateForVelocity(velocityMemberName)))
                {
                    difference = FlatRedBall.Math.MathFunctions.AngleToAngle((float)valueBefore, (float)valueAfter);
                }

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    difference / (float)timeBetween,
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(double))
            {
                double difference = (double)valueAfter - (double)valueBefore;

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    difference / (double)timeBetween,
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(int))
            {
                int difference = (int)valueAfter - (int)valueBefore;
                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    (int)(difference / (double)timeBetween),
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(long))
            {
                long difference = ((long)valueAfter - (long)valueBefore);

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    (long)(difference / (double)timeBetween),
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(byte))
            {
                byte difference = (byte)((byte)valueAfter - (byte)valueBefore);

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    (byte)(difference / (double)timeBetween),
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(Vector2))
            {
                Vector2 range = (Vector2)valueAfter - (Vector2)valueBefore;
                range.X /= (float)timeBetween;
                range.Y /= (float)timeBetween;

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    range,
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(Vector3))
            {
                Vector3 range = (Vector3)valueAfter - (Vector3)valueBefore;
                range.X /= (float)timeBetween;
                range.Y /= (float)timeBetween;
                range.Z /= (float)timeBetween;

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    range,
                    instructionTime
                };
            }
            else if (typeOfValue == typeof(Vector4))
            {
                Vector4 range = (Vector4)valueAfter - (Vector4)valueBefore;
                range.X /= (float)timeBetween;
                range.Y /= (float)timeBetween;
                range.Z /= (float)timeBetween;
                range.W /= (float)timeBetween;

                arguments = new object[]
                {
                    target,
                    velocityMemberName,
                    range,
                    instructionTime
                };
            }

#if XBOX360
            ConstructorInfo ctor = type.GetConstructor(
                BindingFlags.Instance | BindingFlags.Public,
                null,
                new Type[] { typeOfTarget, typeof(string), typeOfValue, typeof(double) },
                null);

            return((Instruction)ctor.Invoke(arguments));
#else
            return((Instruction)Activator.CreateInstance(type, arguments));
#endif
        }
        public InstructionList CreateVelocityListAtIndex(int keyframeIndex)
        {
            if (keyframeIndex > Count - 1)
            {
                // The user passed either the last instruction index or an out-of-bounds index,
                // so return an empty list.
                return(new InstructionList(0));
            }

            else
            {
                #region Get keyframeAtIndex and keyframeAfter

                InstructionList keyframeAtIndex = this[keyframeIndex];

                InstructionList keyframeAfter = null;

                double timeBetween;

                if (keyframeIndex == Count - 1)
                {
                    // If it's the last keyframe, use the same keyframe to stop all velocity
                    keyframeAfter = keyframeAtIndex;
                    timeBetween   = 1; // To prevent NaN values
                }
                else
                {
                    keyframeAfter = this[keyframeIndex + 1];
                    timeBetween   = keyframeAfter[0].TimeToExecute - keyframeAtIndex[0].TimeToExecute;
                }
                #endregion

                InstructionList instructionList = new InstructionList();

                #region Loop through all instructions and create interpolation instructions

                for (int i = 0; i < keyframeAtIndex.Count; i++)
                {
                    Instruction        instructionAtIndex          = keyframeAtIndex[i];
                    GenericInstruction instructionAtIndexAsGeneric = instructionAtIndex as GenericInstruction;

                    Type typeOfTarget = instructionAtIndexAsGeneric.Target.GetType();

                    bool shouldInterpolate =
                        instructionAtIndexAsGeneric.MemberValueAsObject != null &&

                        instructionAtIndexAsGeneric != null &&
                        InstructionManager.HasInterpolatorForType(
                            instructionAtIndexAsGeneric.MemberValueAsObject.GetType());

                    string velocityMemberName = InstructionManager.GetVelocityForState(
                        instructionAtIndexAsGeneric.Member);

                    if (shouldInterpolate && !string.IsNullOrEmpty(velocityMemberName))
                    {
                        Type typeOfValue = instructionAtIndexAsGeneric.MemberValueAsObject.GetType();
                        //bool hasInterpolated = false;

                        GenericInstruction instructionAfterAsGeneric = keyframeAfter[i] as GenericInstruction;

                        if (instructionAfterAsGeneric != null &&
                            instructionAtIndexAsGeneric.Target == instructionAfterAsGeneric.Target &&
                            instructionAtIndexAsGeneric.Member == instructionAfterAsGeneric.Member)
                        {
                            // We've found the instruction!  Create a velocity instruction
                            Instruction instruction = CreateInstructionFor(
                                instructionAtIndexAsGeneric.Target,
                                velocityMemberName,
                                instructionAtIndexAsGeneric.MemberValueAsObject,
                                instructionAfterAsGeneric.MemberValueAsObject,
                                timeBetween,
                                instructionAtIndexAsGeneric.TimeToExecute,
                                typeOfTarget,
                                typeOfValue);

                            instruction.TimeToExecute = instructionAtIndex.TimeToExecute;

                            instructionList.Add(instruction);
                        }
                    }
                    // switch on the Type, but can't use a Switch statement
                }
                #endregion

                return(instructionList);
            }
        }
        public void SetState(double time, bool setVelocity)
        {
            InstructionList keyframeBefore = KeyframeAtOrBefore(time);
            InstructionList keyframeAfter  = KeyframeAtOrAfter(time);

            if (keyframeBefore == null && keyframeAfter == null)
            {
                return;
            }

            else if (keyframeBefore == keyframeAfter)
            {
                keyframeBefore.Execute();
            }
            else if (keyframeBefore != null && keyframeAfter == null)
            {
                keyframeBefore.Execute();
            }
            else if (keyframeAfter != null && keyframeBefore == null)
            {
                keyframeAfter.Execute();
            }
            else // the two keyframes are not the same, and neither are null
            {
                double timeAfter  = keyframeAfter[0].TimeToExecute;
                double timeBefore = keyframeBefore[0].TimeToExecute;

                double range = timeAfter - timeBefore;

                double ratioAfter  = (time - timeBefore) / range;
                double ratioBefore = 1 - ratioAfter;

                for (int i = 0; i < keyframeBefore.Count; i++)
                {
                    Instruction instructionBefore = keyframeBefore[i];

                    GenericInstruction instructionBeforeAsGeneric = instructionBefore as GenericInstruction;

                    object memberValueAsObject = instructionBeforeAsGeneric.MemberValueAsObject;
                    // DO MORE HERE

                    bool shouldInterpolate =
                        instructionBeforeAsGeneric.MemberValueAsObject != null &&
                        instructionBeforeAsGeneric != null &&
                        InstructionManager.HasInterpolatorForType(
                            instructionBeforeAsGeneric.MemberValueAsObject.GetType());

                    if (shouldInterpolate)
                    {
                        bool hasInterpolated = false;

                        GenericInstruction instructionAfterAsGeneric =
                            keyframeAfter[i] as GenericInstruction;

                        if (instructionAfterAsGeneric != null &&
                            instructionBeforeAsGeneric.Target == instructionAfterAsGeneric.Target &&
                            instructionBeforeAsGeneric.Member == instructionAfterAsGeneric.Member)
                        {
                            // We've found the instruction!  Interpolate!
                            instructionBeforeAsGeneric.InterpolateBetweenAndExecute(instructionAfterAsGeneric, (float)ratioBefore);

                            hasInterpolated = true;
                        }

                        if (hasInterpolated == false)
                        {
                            // for now, fail.  Eventually will want to search the entire KeyframeAfter to see if it
                            // contains a matching instruction for interpolation
                            throw new NotImplementedException("The keyframes instructions do not match up.  Cannot interpolate.");
                        }
                    }
                    else
                    {
                        keyframeBefore[i].Execute();
                    }
                }
            }
        }