File: System\Activities\Statements\StateMachineEventManager.cs
Project: ndp\cdf\src\NetFx40\System.Activities\System.Activities.csproj (System.Activities)
//------------------------------------------------------------------------------
// <copyright file="StateMachineEventManager.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Activities.Statements
{
    using System;
    using System.Activities;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Runtime.Serialization;
    
    /// <summary>
    /// StateMachineEventManager is used to manage triggered events globally.
    /// </summary>
    [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses",
        Justification = "This type is actually used in LINQ expression and FxCop didn't detect that.")]
    [DataContract]
    class StateMachineEventManager
    {
        // To avoid out of memory, set a fixed length of event queue.
        const int MaxQueueLength = 1 << 25;
 
        // queue is used to store triggered events
        Queue<TriggerCompletedEvent> queue;
        
        // If a state is running, its condition evaluation bookmark will be added in to activityBookmarks.
        // If a state is completed, its bookmark will be removed.
        Collection<Bookmark> activeBookmarks;     
 
        /// <summary>
        /// Constructor to do initialization.
        /// </summary>
        public StateMachineEventManager()
        {
            this.queue = new Queue<TriggerCompletedEvent>();
            this.activeBookmarks = new Collection<Bookmark>();
        }
 
        /// <summary>
        /// Gets or sets the trigger index of current being processed event.
        /// </summary>
        [DataMember(EmitDefaultValue = false)]
        public TriggerCompletedEvent CurrentBeingProcessedEvent
        {
            get;
            set;
        }
 
        /// <summary>
        /// Gets or sets the CurrentConditionIndex denotes the index of condition is being evaluated.
        /// </summary>
        [DataMember(EmitDefaultValue = false)]
        public int CurrentConditionIndex
        {
            get;
            set;
        }
 
        /// <summary>
        /// Gets or sets a value indicating whether StateMachine is on the way of transition.
        /// </summary>
        [DataMember(EmitDefaultValue = false)]
        public bool OnTransition
        {
            get;
            set;
        }
 
        /// <summary>
        /// Gets the EventManager queue.
        /// </summary>
        public IEnumerable<TriggerCompletedEvent> Queue
        {
            get
            {
                return this.queue;
            }
        }
 
        /// <summary>
        /// Gets a value indicating whether StateMachineManger is ready to process an event immediately.
        /// </summary>
        bool CanProcessEventImmediately
        {
            get
            {
                return this.CurrentBeingProcessedEvent == null && !this.OnTransition && this.queue.Count == 0;
            }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "queue")]
        internal Queue<TriggerCompletedEvent> SerializedQueue
        {
            get { return this.queue; }
            set { this.queue = value; }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "activeBookmarks")]
        internal Collection<Bookmark> SerializedActiveBookmarks
        {
            get { return this.activeBookmarks; }
            set { this.activeBookmarks = value; }
        }
 
        /// <summary>
        /// When StateMachine enters a state, condition evaluation bookmark of that state would be added to activeBookmarks collection.
        /// </summary>
        /// <param name="bookmark">Bookmark reference.</param>
        public void AddActiveBookmark(Bookmark bookmark)
        {
            this.activeBookmarks.Add(bookmark);
        }
 
        /// <summary>
        /// Gets next completed events queue.
        /// </summary>
        /// <returns>Top TriggerCompletedEvent item in the queue.</returns>
        public TriggerCompletedEvent GetNextCompletedEvent()
        {
            while (this.queue.Any())
            {
                TriggerCompletedEvent completedEvent = this.queue.Dequeue();
                if (this.activeBookmarks.Contains(completedEvent.Bookmark))
                {
                    this.CurrentBeingProcessedEvent = completedEvent;
                    return completedEvent;
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// This method is used to denote whether a given bookmark is referred by currently processed event.
        /// </summary>
        /// <param name="bookmark">Bookmark reference.</param>
        /// <returns>True is the bookmark references to the event being processed.</returns>
        public bool IsReferredByBeingProcessedEvent(Bookmark bookmark)
        {
            return this.CurrentBeingProcessedEvent != null && this.CurrentBeingProcessedEvent.Bookmark == bookmark;
        }
 
        /// <summary>
        /// Register a completed event and returns whether the event could be processed immediately.
        /// </summary>
        /// <param name="completedEvent">TriggerCompletedEvent reference.</param>
        /// <param name="canBeProcessedImmediately">True if the Condition can be evaluated.</param>
        public void RegisterCompletedEvent(TriggerCompletedEvent completedEvent, out bool canBeProcessedImmediately)
        {
            canBeProcessedImmediately = this.CanProcessEventImmediately;
            this.queue.Enqueue(completedEvent);
            return;
        }
 
        /// <summary>
        /// When StateMachine leaves a state, condition evaluation bookmark of that state would be removed from activeBookmarks collection.
        /// </summary>
        /// <param name="bookmark">Bookmark reference.</param>
        public void RemoveActiveBookmark(Bookmark bookmark)
        {
            this.activeBookmarks.Remove(bookmark);
        }
    }
}