File: StateMachineExecutionState.cs
Project: ndp\cdf\src\WF\Activities\System.Workflow.Activities.csproj (System.Workflow.Activities)
#region Using directives
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.Remoting.Messaging;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
 
#endregion Using directives
 
namespace System.Workflow.Activities
{
    [Serializable]
    internal class StateMachineExecutionState
    {
        #region Member Variables
 
        internal const string StateMachineExecutionStateKey = "StateMachineExecutionState";
        private StateMachineSubscriptionManager _subscriptionManager;
        private Queue<StateMachineAction> _actions;
        private string _currentStateName;
        private string _previousStateName;
        private string _nextStateName;
        private bool _completed = false;
        private bool _queueLocked = false;
        private bool _schedulerBusy = false;
 
        #endregion Member Variables
 
        #region Properties
 
        internal StateMachineSubscriptionManager SubscriptionManager
        {
            get
            {
                return _subscriptionManager;
            }
        }
 
        private Queue<StateMachineAction> Actions
        {
            get
            {
                if (_actions == null)
                    _actions = new Queue<StateMachineAction>();
                return _actions;
            }
        }
 
        internal bool SchedulerBusy
        {
            get
            {
                return _schedulerBusy;
            }
            set
            {
                _schedulerBusy = value;
            }
        }
 
        internal string CurrentStateName
        {
            get
            {
                return _currentStateName;
            }
            set
            {
                _currentStateName = value;
            }
        }
 
        internal string PreviousStateName
        {
            get
            {
                return _previousStateName;
            }
            set
            {
                _previousStateName = value;
            }
        }
 
        internal string NextStateName
        {
            get
            {
                return _nextStateName;
            }
            set
            {
                _nextStateName = value;
            }
        }
 
        internal bool Completed
        {
            get
            {
                return _completed;
            }
            set
            {
                _completed = value;
            }
        }
 
        internal bool HasEnqueuedActions
        {
            get
            {
                return this.Actions.Count > 0;
            }
        }
 
        #endregion Properties
 
        #region Constructors
 
        internal StateMachineExecutionState(Guid instanceId)
        {
            _subscriptionManager = new StateMachineSubscriptionManager(this, instanceId);
        }
 
        #endregion
 
        internal void LockQueue()
        {
            _queueLocked = true;
        }
 
        internal void EnqueueAction(StateMachineAction action)
        {
            Debug.Assert(!this._queueLocked);
            this.Actions.Enqueue(action);
        }
 
        internal StateMachineAction DequeueAction()
        {
            StateMachineAction action = this.Actions.Dequeue();
            if (this.Actions.Count == 0)
                _queueLocked = false;
            return action;
        }
 
        internal void ProcessActions(ActivityExecutionContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
 
            if (this.SchedulerBusy)
                return;
 
            StateActivity state = (StateActivity)context.Activity;
 
            if (this.Actions.Count == 0)
            {
                this.SubscriptionManager.ProcessQueue(context);
                return;
            }
 
            StateMachineAction action = this.Actions.Peek();
            while (action.StateName.Equals(state.QualifiedName))
            {
                action = DequeueAction();
                action.Execute(context);
 
                // If the previous action just
                // requested something to the runtime
                // scheduler, then we quit, since
                // the scheduler takes precedence.
                // we'll pick up the processing of actions
                // after the scheduler return the control to us.
                if (this.SchedulerBusy)
                    return;
 
                if (this.Actions.Count == 0)
                    break;
 
                action = this.Actions.Peek();
            }
 
            if (this.Actions.Count > 0)
            {
                StateActivity rootState = StateMachineHelpers.GetRootState(state);
                StateActivity nextActionState = StateMachineHelpers.FindDynamicStateByName(rootState, action.StateName);
                if (nextActionState == null)
                    throw new InvalidOperationException(SR.GetInvalidStateMachineAction(action.StateName));
 
                nextActionState.RaiseProcessActionEvent(context);
            }
            else
            {
                this.SubscriptionManager.ProcessQueue(context);
            }
        }
 
 
        internal void ProcessTransitionRequest(ActivityExecutionContext context)
        {
            if (String.IsNullOrEmpty(this.NextStateName))
                return;
 
            StateActivity currentState = StateMachineHelpers.GetCurrentState(context);
            CalculateStateTransition(currentState, this.NextStateName);
            LockQueue();
            this.NextStateName = null;
        }
 
        internal void CalculateStateTransition(StateActivity currentState, string targetStateName)
        {
            if (currentState == null)
                throw new ArgumentNullException("currentState");
            if (String.IsNullOrEmpty(targetStateName))
                throw new ArgumentNullException("targetStateName");
 
            while (currentState != null && (currentState.QualifiedName.Equals(targetStateName) || !StateMachineHelpers.ContainsState(currentState, targetStateName)))
            {
                CloseStateAction action = new CloseStateAction(currentState.QualifiedName);
                this.Actions.Enqueue(action);
                currentState = currentState.Parent as StateActivity;
            }
            if (currentState == null)
                throw new InvalidOperationException(SR.GetUnableToTransitionToState(targetStateName));
 
            while (!currentState.QualifiedName.Equals(targetStateName))
            {
                foreach (Activity childActivity in currentState.EnabledActivities)
                {
                    StateActivity childState = childActivity as StateActivity;
                    if (childState != null)
                    {
                        // 
                        if (StateMachineHelpers.ContainsState(childState, targetStateName))
                        {
                            ExecuteChildStateAction action = new ExecuteChildStateAction(currentState.QualifiedName, childState.QualifiedName);
                            this.Actions.Enqueue(action);
                            currentState = childState;
                            break;
                        }
                    }
                }
            }
            if (!StateMachineHelpers.IsLeafState(currentState))
                throw new InvalidOperationException(SR.GetInvalidStateTransitionPath());
        }
 
        #region Static Methods
 
        internal static StateMachineExecutionState Get(StateActivity state)
        {
            Debug.Assert(StateMachineHelpers.IsRootState(state));
            StateMachineExecutionState executionState = (StateMachineExecutionState)state.GetValue(StateActivity.StateMachineExecutionStateProperty);
            Debug.Assert(executionState != null);
            return executionState;
        }
 
        #endregion
    }
}