public AnimatedStateSave ToAnimatedStateSave()
        {
            AnimatedStateSave toReturn = new AnimatedStateSave();

            if(string.IsNullOrEmpty(StateName))
            {
                throw new InvalidOperationException("Could not convert this to a AnimatedStateSave because it doesn't have a valid StateName");
            }

            toReturn.StateName = this.StateName;
            toReturn.Time = this.Time;
            toReturn.InterpolationType = this.InterpolationType;
            toReturn.Easing = this.Easing;

            return toReturn;
        }
        public static AnimatedKeyframeViewModel FromSave(AnimatedStateSave save)
        {
            AnimatedKeyframeViewModel toReturn = new AnimatedKeyframeViewModel();

            toReturn.StateName = save.StateName;
            toReturn.Time = save.Time;
            toReturn.InterpolationType = save.InterpolationType;
            toReturn.Easing = save.Easing;

            return toReturn;
        }
        private void CreateInstructionForInterpolationRelative(StateCodeGeneratorContext context, ICodeBlock currentBlock, AnimatedStateSave previousState, AnimatedStateSave currentState)
        {
            if(previousState != null)
            {
                currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(() =>");
                {
                    currentBlock = currentBlock.Block();

                    // Is the start clone necessary?
                    currentBlock.Line("var relativeStart = ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + previousState.StateName + "\").Clone();");
                    currentBlock.Line("var relativeEnd = ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + currentState.StateName + "\").Clone();");
                    currentBlock.Line("Gum.DataTypes.Variables.StateSaveExtensionMethods.SubtractFromThis(relativeEnd, relativeStart);");
                    currentBlock.Line("var difference = relativeEnd;");

                    string categoryName = "VariableState";
                    var category = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandidate => stateCandidate.Name == currentState.StateName));

                    string enumValue = currentState.StateName;

                    if(currentState.StateName.Contains('/'))
                    {
                        var split = currentState.StateName.Split('/');

                        category = context.Element.Categories.FirstOrDefault(item => item.Name == split[0]);
                        enumValue = split[1];
                    }

                    if(category != null)
                    {
                        categoryName = category.Name;
                    }
                    currentBlock.Line("Gum.DataTypes.Variables.StateSave first = GetCurrentValuesOnState(" + categoryName + "." + enumValue + ");");

                    currentBlock.Line("Gum.DataTypes.Variables.StateSave second = first.Clone();");
                    currentBlock.Line("Gum.DataTypes.Variables.StateSaveExtensionMethods.AddIntoThis(second, difference);");


                    string interpolationTime = ToFloatString(currentState.Time - previousState.Time);

                    string easing = "FlatRedBall.Glue.StateInterpolation.Easing." + previousState.Easing;
                    string interpolationType = "FlatRedBall.Glue.StateInterpolation.InterpolationType." + previousState.InterpolationType;


                    currentBlock.Line(
                        string.Format("FlatRedBall.Glue.StateInterpolation.Tweener tweener = new FlatRedBall.Glue.StateInterpolation.Tweener(from: 0, to: 1, duration: {0}, type: {1}, easing: {2});",
                        interpolationTime,
                        interpolationType,
                        easing));

                    currentBlock.Line("tweener.Owner = this;");

                    currentBlock.Line("tweener.PositionChanged = newPosition => this.InterpolateBetween(first, second, newPosition);");
                    currentBlock.Line("tweener.Start();");
                    currentBlock.Line("StateInterpolationPlugin.TweenerManager.Self.Add(tweener);");


                    currentBlock = currentBlock.End();
                }
                currentBlock.Line(");");
                string previousStateTime = ToFloatString(previousState.Time);

                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + previousStateTime + ";");
                currentBlock.Line("yield return toReturn;");
                
            }
        }
        private void CreateInstructionForInterpolationAbsolute(StateCodeGeneratorContext context, ICodeBlock currentBlock, string animationType, AnimatedStateSave previousState, AnimatedStateSave currentState, string animationName)
        {

            if (previousState == null)
            {
                string variableStateName = null;

                variableStateName = "CurrentVariableState";

                if (currentState.StateName.Contains("/"))
                {
                    var split = currentState.StateName.Split('/');
                    animationType = split[0];
                }

                if (animationType != "VariableState")
                {
                    variableStateName = "Current" + animationType + "State";
                }

                // todo:  Change this on categories
                //System.Action action = () => this.CurrentState = fromState;

                string enumValue = currentState.StateName;
                if(enumValue.Contains("/"))
                {
                    enumValue = enumValue.Split('/')[1];
                }

                currentBlock.Line("var toReturn = new FlatRedBall.Instructions.DelegateInstruction( ()=> this." + variableStateName + " = " +
                    animationType + "." + enumValue + ");");
                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime;");

            }
            else
            {
                var previousCategory = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandiate => stateCandiate.Name == previousState.StateName));
                var currentCategory = context.Element.Categories.FirstOrDefault(item => item.States.Any(stateCandiate => stateCandiate.Name == currentState.StateName));

                // Now that we interpolateTo a single state, we don't
                // need to pass in the StateSave object:
                //bool differentCategories = previousCategory != currentCategory;

                // November 3, 2015
                // Gum uses a "cumulative 
                // state" system, so that each 
                // keyframe in an animation will 
                // tween with variables both before 
                // and after.
                // The code as of the time of the writing 
                // of this comment does InterpolateBetween
                // two states, which does not consider the state
                // of the object and only tweens variables common
                // to the two states. This makes the runtime behave
                // different than Glue, and it also makes the runtime
                // behave in confusing ways as authors don't often think
                // about the individual variables that may be set in a state.
                // We can solve this by instead doing Interpolate to between the
                // current state of the instance and the state that we are interpolating
                // to. Going to accomplish this by getting rid of the "from" state:
                //string fromState = null;

                string toState = null;

                string enumValue = currentState.StateName;
                if(currentState.StateName.Contains("/"))
                {
                    currentCategory = context.Element.Categories.FirstOrDefault(item => item.Name == currentState.StateName.Split('/')[0]);
                    enumValue = currentState.StateName.Split('/')[1];
                }


                //if (differentCategories)
                //{
                //fromState = "this.ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + previousState.StateName + "\")";
                //toState = "this.ElementSave.AllStates.FirstOrDefault(item => item.Name == \"" + currentState.StateName + "\")";
                //}
                //else
                //{
                //fromState = animationType + "." + previousState.StateName;
                if (currentCategory == null)
                {
                    toState = "VariableState." + enumValue;

                }
                else
                {
                    toState = currentCategory.Name + "." + enumValue;
                }
                //}

                string previousStateTime = ToFloatString(previousState.Time);

                string interpolationTime = ToFloatString(currentState.Time - previousState.Time);

                string easing = "FlatRedBall.Glue.StateInterpolation.Easing." + previousState.Easing;
                string interpolationType = "FlatRedBall.Glue.StateInterpolation.InterpolationType." + previousState.InterpolationType;

                var line = "var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(" +
                    string.Format("{0}, {1}, {2}, {3}, {4}));", toState, interpolationTime, interpolationType, easing, animationName);

                // vic says - 
                // For some reason I'm getting some weird code generation issues when generating one of my objects for the racing game
                // I don't have perfect repro steps, so I wanted to catch it in the debugger:

                //var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(VariableState.Shown, 0.25f, FlatRedBall.Glue.StateInterpolation.InterpolationType.Linear, FlatRedBall.Glue.StateInterpolation.Easing.Out, FadeInAnimation));
                if (line.Contains("var toReturn = new FlatRedBall.Instructions.DelegateInstruction(  () => this.InterpolateTo(VariableState.Shown, 0.25f, FlatRedBall.Glue.StateInterpolation.InterpolationType.Linear, FlatRedBall.Glue.StateInterpolation.Easing.Out, FadeInAnimation));"))
                {
                    int m = 3;
                }

                
                currentBlock.Line(line);
                currentBlock.Line("toReturn.TimeToExecute = FlatRedBall.TimeManager.CurrentTime + " + previousStateTime + ";");

            }
            currentBlock.Line("yield return toReturn;");
            //System.Action action = () => this.InterpolateTo(fromState, toState, timeToTake, interpolationType, easing);
        }
        private void CreateInstructionForInterpolation(StateCodeGeneratorContext context, ICodeBlock currentBlock, string animationType, AnimatedStateSave previousState, AnimatedStateSave currentState, AbsoluteOrRelative absoluteOrRelative, string animationName)
        {

            currentBlock = currentBlock.Block();

            if (absoluteOrRelative == AbsoluteOrRelative.Absolute)
            {

                CreateInstructionForInterpolationAbsolute(context, currentBlock, animationType, previousState, currentState, animationName);
            }
            else
            {
                CreateInstructionForInterpolationRelative(context,currentBlock,  previousState, currentState);
            }
            currentBlock = currentBlock.End();
        }