/// <summary>
 /// Attempts to advance to a new state, checking for unknown and null states.
 /// </summary>
 /// <param name="nextState">The name of the state to go to (as sent to AddState).</param>
 protected void AdvanceToState(String nextState)
 {
     // If they passed a value state name...
     if (!String.IsNullOrEmpty(nextState))
     {
         // ...and it is one that we are managing.
         if (mStates.ContainsKey(nextState))
         {
             // Request a new state and move to the END pass of this flow.
             mNextState = mStates[nextState];
             mCurrentFlowState = FlowStates.END;
         }
         else
         {
             System.Diagnostics.Debug.Assert(false, "FSMState returned a new state which is not managed by this state machine: " + nextState);
         }
     }
 }
 /// <summary>
 /// Called by GameObjectFactory when object is recycled.
 /// </summary>
 public override void Reset()
 {
     mCurrentState = mNextState = mInitialState;
     mCurrentFlowState = FlowStates.INITIAL_STATE;
 }
        /// <summary>
        /// Interface for adding new FSMState to this FiniteStateMachine.
        /// </summary>
        /// <param name="state">Implementation of the FSMState.</param>
        /// <param name="id">An indentifier used to manage and transition between states.</param>
        protected void AddState(FSMState state, String id)
        {
            // The state will be expecting to access the Parent GameObject a lot.
            state.pParentGOH = mParentGOH;

            // Check for duplicate entries.
            if (mStates.ContainsKey(id))
            {
                System.Diagnostics.Debug.Assert(false, "Attempting to add two FSMState objects with the same ID to a FiniteStateMachine: " + id);

                return;
            }
            else
            {
                // Add it to our list of states.
                mStates.Add(id, state);
            }

            // If this is the first state to be added, use it as the initial FSMState to be run.
            if (mCurrentState == null)
            {
                mInitialState = mCurrentState = mNextState = state;
                mCurrentFlowState = FlowStates.INITIAL_STATE;
            }
        }
        /// <summary>
        /// Called once per frame by the game object.
        /// </summary>
        /// <param name="gameTime">The amount of time that has passed this frame.</param>
        public override void Update(GameTime gameTime)
        {
            // The basic flow for every state machine:
            //  1) Run OnBegin (1 frame).
            //  2) Run OnUpdate (Indefinitly; until it returns a new state to transition to).
            //  3) Run OnEnd (1 frame).
            //
            switch (mCurrentFlowState)
            {
            case FlowStates.BEGIN:
                {
                    // Transition directly to the UPDATE pass. Do it before calling OnBegin incase
                    // OnBegin actually sets the current state through a message, in which case we
                    // don't want to go to UPDATE.
                    mCurrentFlowState = FlowStates.UPDATE;

                    mCurrentState.OnBegin();

                    break;
                }
            case FlowStates.UPDATE:
                {
                    // Update the state which will potentially return a new state in which to transition to.
                    String nextState = mCurrentState.OnUpdate();

                    AdvanceToState(nextState);

                    break;
                }
            case FlowStates.END:
                {
                    mCurrentState.OnEnd();

                    // Once the FlowStates.END has finished it is time to move onto the next FSMState.
                    mCurrentState = mNextState;

                    // On the next update pass we will be running a new FSMState, so we want to be sitting
                    // in the BEGIN flow state.
                    mCurrentFlowState = FlowStates.BEGIN;

                    break;
                }
            default:
                {
                    System.Diagnostics.Debug.Assert(false, "Unhandled FSM Flow State.");

                    break;
                }
            }

            // Keep going until we get to an update state. This is to avoid objects popping out and
            // in between states.
            if (mCurrentFlowState != FlowStates.UPDATE)
            {
                Update(gameTime);
            }
        }