#region --------------- Copyright Dresser Wayne Pignone ------------- /* * $Log: /Wrk/WayneLibraries/Wrk/StateEngine/CompositeState.cs $ * * 7 08-03-25 14:15 Mattias.larsson * Clean-up. * * 6 08-02-26 14:06 Mattias.larsson * Renamed stateName to factoryName. * * 5 07-08-15 15:27 roger.månsson * Added SetDebugLogger method. * * 4 07-08-07 8:26 Mattias.larsson * * 3 07-03-02 13:19 roger.månsson */ #endregion #region Old file header /*=============================================================================== * CompositeState * * Change history * When Who Comment * ---------- ------ ------------------------------------ * 2006-07-17 RMa Major updates, Changed state machine and event handling. * 2006-05-09 RMa Implemented the dispose handling. * 2006-03-01 RMa FXCop updates: CreateStateMachine is not virtual anymore. * 2006-02-03 RMa FXCop updates: Made constuctor protected + misc. * 2006-01-27 RMa Removed interface Event. Use Event class instead. * 2006-01-05 RMa Added the internal function LookupState * 2005-12-14 RMa Changed so Internal_Enter is called by the state machine, so we are sure that * the internal stuff gets called ,if the user forgets to call base.Enter().... * 2005-12-09 RMa Fixed so the state entry always is sent into a composite state machine. * 2005-12-05 RMa This header added. * ---------------------------------------------------------------------------------*/ #endregion using System; using System.Linq; using Wayne.Lib.Log; namespace Wayne.Lib.StateEngine { /// /// Composite state is an abstract class that should be overriden to /// create a state that within itself have a state machine with sub states. /// When creating the composite state, a message handling thread should be sent /// in to the composite state constructor. It can either be a new thread if the /// composite state machine should run in a separate thread , or the thread of the /// parent state machine if the machine should run in the same thread. /// abstract public class CompositeState : State { #region Fields private StateMachine stateMachine; private bool disposed; #endregion #region Construction /// /// Initializes a new instance of a composite state. /// protected CompositeState() { stateMachine = new CompositeStateMachine(this); } /// /// Destructor /// ~CompositeState() { Dispose(false); } #endregion #region Methods /// /// Handles an incoming event. /// /// Event that is received. /// Perform a transaction by assigning a transition object to this ref parameter. protected sealed override void HandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition) { BeforeHandleEvent(stateEngineEvent, ref transition); if (!stateEngineEvent.Handled) stateMachine.HandleEvent(stateEngineEvent, ref transition); if (!stateEngineEvent.Handled) UnhandledEvent(stateEngineEvent, ref transition); } /// /// Method that can be overriden in descendant classes, so events can be handed before they are sent to the /// state machine. /// /// /// Perform a transaction by assigning a transition object to this ref parameter. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")] public virtual void BeforeHandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition) { } /// /// Method that can be overriden if wanting to handle events that not has been handled in the composite state machine. /// /// /// Perform a transaction by assigning a transition object to this ref parameter. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")] public virtual void UnhandledEvent(StateEngineEvent stateEngineEvent, ref Transition transition) { } #endregion #region Internal Methods internal override void PerformEnter(StateEntry entry, ref Transition transition) { base.PerformEnter(entry, ref transition); if (!stateMachine.Initialized) this.Initialize(); //If base did not result in any transition, if (transition == null) { stateMachine.EnterState(entry, ref transition); if (transition != null) stateMachine.HandleTransition(ref transition); } } internal override void PerformExit() { base.PerformExit(); stateMachine.ExitState(); } /// /// Initializes and creates the states of the composite state engine. /// internal void Initialize() { if (!stateMachine.Initialized) stateMachine.Initialize(); } /// /// This function is used to locate a specific state in the state machine. /// /// The composite state checks first if its own FactoryName matches the name, /// if not it calls each created state subsequently. /// /// The name of the state that should be looked up. /// True if the state is or contains a state with this name. internal override bool LookupState(string factoryName) { if (base.LookupState(factoryName)) return true; foreach (State state in StateMachine.CreatedStates) { if (state.LookupState(factoryName)) return true; } return false; } /// /// Internal dispose method. /// /// protected override void Dispose(bool disposing) { try { if (!disposed) { disposed = true; if (disposing) stateMachine.Dispose(); } } finally { base.Dispose(disposing); } } #endregion #region Properties /// /// Returns the state machine that is used with the Composite state. /// public StateMachine StateMachine { get { return stateMachine; } } /// /// Set the parent state machine for the state. /// internal override void SetParentStateMachine(StateMachine parentStateMachine) { base.SetParentStateMachine(parentStateMachine); this.stateMachine.ParentStateMachine = parentStateMachine; } /// /// Set the debug logger for the composite state, and assign it on to the state machine. /// /// /// internal override void SetDebugLogger(IDebugLogger debugLogger, object logCategory) { base.SetDebugLogger(debugLogger, logCategory); this.stateMachine.SetDebugLogger(debugLogger, logCategory); } public override string Name { get { return GetType().Namespace.Split('.').LastOrDefault() ?? base.Name; } } #endregion } }