#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
}
}