12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088 |
- #region --------------- Copyright Dresser Wayne Pignone -------------
- #endregion
- #region Old change history
- #endregion
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Wayne.Lib.Log;
- namespace Wayne.Lib.StateEngine
- {
-
-
-
-
-
-
- public abstract class StateMachine : IEventConsumer, IDisposable
- {
- #region Fields
- private const bool TimerWrapperCaching = false;
- private InitialState initialState;
- private Dictionary<string, State> createdStates = new Dictionary<string, State>();
- private State currentState;
- private StateTransitionLookup stateLookup;
- internal StateFactories stateFactories = new StateFactories();
- private StateTypeContainer stateTypeContainer;
- internal List<TimerWrapper> timerWrapperList = new List<TimerWrapper>();
- private object timerWrapperListLock = new object();
- private EventHandler timerOnEnableEventHandler;
- private EventHandler timerOnDisableEventHandler;
- private StateMachine parentStateMachine;
- private int depth;
- private bool initialized;
- private object initalizeLock = new object();
- private string name;
- private StateNameKind logNameKind;
- private StateMachine mainStateMachine;
-
-
-
- protected internal bool disposed;
-
-
-
- internal protected IDebugLogger debugLogger;
-
-
-
- internal protected object logCategory;
- #endregion
- #region Events
-
-
-
- public event EventHandler<StateChangedEventArgs> OnStateChange;
-
-
-
- public event EventHandler<StateChangedEventArgs> OnStateChanged;
-
-
-
- public event EventHandler OnFinalStateEntered;
- #endregion
- #region Construction
-
-
-
- internal StateMachine(string name, IDebugLogger debugLogger, object logCategory)
- {
- this.name = name;
- this.debugLogger = debugLogger;
- this.logCategory = logCategory;
- this.stateTypeContainer = new StateTypeContainer();
- stateLookup = new StateTransitionLookup(stateTypeContainer);
- timerOnDisableEventHandler = new EventHandler(timer_OnDisable);
- timerOnEnableEventHandler = new EventHandler(timer_OnEnable);
- }
-
-
-
- ~StateMachine()
- {
- Dispose(false);
- }
- #endregion
- #region Public Methods
-
-
-
-
-
- public abstract void Start();
-
-
-
-
- public abstract void IncomingEvent(StateEngineEvent stateEngineEvent);
-
-
-
-
-
- public virtual IEnumerable<StateEngineEvent> GetPendingEventsOfType(object eventType)
- {
- return parentStateMachine != null ? parentStateMachine.GetPendingEventsOfType(eventType) : null;
- }
-
-
-
-
-
-
- public virtual void RemovePendingEventsOfType(object eventType)
- {
- if (parentStateMachine != null)
- parentStateMachine.RemovePendingEventsOfType(eventType);
- }
-
-
-
-
-
-
- public virtual void RemovePendingEvents<TComparisonObject>(StateEngineEventPredicate<TComparisonObject> predicate, TComparisonObject comparisonObject)
- {
- if (parentStateMachine != null)
- parentStateMachine.RemovePendingEvents(predicate, comparisonObject);
- }
-
-
-
-
-
-
-
- public virtual IEnumerable<StateEngineEvent> GetPendingEvents<TComparisonObject>(
- StateEngineEventPredicate<TComparisonObject> predicate, TComparisonObject comparisonObject)
- {
- return parentStateMachine != null ? parentStateMachine.GetPendingEvents(predicate, comparisonObject) : null;
- }
-
-
-
-
- public override string ToString()
- {
- return name;
- }
- #endregion
- #region State factory methods
-
-
-
- public void ClearStateFactories()
- {
- stateFactories.Clear();
- }
-
-
-
-
-
- public void AddStateFactory(IStateFactory factory)
- {
- stateFactories.AddFactory(factory);
- }
- #endregion
- #region Private Methods
-
-
-
-
-
-
-
-
-
-
- private void PerformStateChange(State newState, Wayne.Lib.StateEngine.StateEntry entry, ref Transition transition)
- {
-
- State oldState = currentState;
- CheckAndRemoveTimersForCurrentState();
-
- currentState = newState;
-
- if ((oldState != null) && oldState.Active)
- oldState.PerformExit();
- StateChangedEventArgs stateChangeEventArgs = new StateChangedEventArgs(oldState, newState, entry.SourceTransition);
-
- if (OnStateChange != null)
- OnStateChange.Invoke(this, stateChangeEventArgs);
-
- currentState.PerformEnter(entry, ref transition);
-
- if (OnStateChanged != null)
- OnStateChanged.Invoke(this, stateChangeEventArgs);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- private State GetState(string stateFactoryName)
- {
- State result;
- if (!createdStates.TryGetValue(stateFactoryName, out result))
- {
- createdStates.Add(stateFactoryName, result = CreateState(stateFactoryName));
- }
- return result;
- }
-
-
-
-
-
- internal protected virtual State CreateState(string stateFactoryName)
- {
- State newState = stateFactories.CreateState(stateFactoryName, stateTypeContainer);
- if (newState == null && ParentStateMachine != null)
- newState = ParentStateMachine.stateFactories.CreateState(stateFactoryName, stateTypeContainer);
- if (newState == null && MainStateMachine != null)
- MainStateMachine.stateFactories.CreateState(stateFactoryName, stateTypeContainer);
- if (newState != null)
- {
- newState.WritableFactoryName = stateFactoryName;
- newState.SetParentStateMachine(this);
- newState.SetDebugLogger(debugLogger, logCategory);
- }
- return newState;
- }
-
-
-
-
-
- private void CreateStateObjects()
- {
- string[] stateFactoryNames = stateLookup.GetStateNameList(false);
- foreach (string stateFactoryName in stateFactoryNames)
- {
- State state = this.GetState(stateFactoryName);
- if (state != null)
- {
- InitialState tempInitState = state as InitialState;
- if (tempInitState != null)
- {
- initialState = tempInitState;
- }
- else
- {
- CompositeState compositeState = state as CompositeState;
- if (compositeState != null)
- {
- compositeState.Initialize();
- }
- }
- }
- else
- {
- throw new InvalidOperationException("Can not create state " + stateFactoryName);
- }
- }
- }
- #endregion
- #region Public Properties
-
-
-
- public StateTransitionLookup StateTransitionLookup
- {
- get { return stateLookup; }
- }
-
-
-
-
- public int Depth
- {
- get { return depth; }
- set { depth = value; }
- }
-
-
-
- public State CurrentState
- {
- get { return currentState; }
- }
-
-
-
- public State CurrentStateRecursive
- {
- get
- {
- return GetStateRecursively(currentState);
- }
- }
- private State GetStateRecursively(State state)
- {
- if (state is CompositeState)
- {
- var compositeState = ((CompositeState)state);
- if (compositeState.StateMachine.CurrentState == null)
- return compositeState;
- else
- return GetStateRecursively(compositeState.StateMachine.CurrentState);
- }
- else
- {
- return state;
- }
- }
-
-
-
- public System.Collections.ObjectModel.ReadOnlyCollection<State> CreatedStates
- {
- get { return createdStates.Values.ToList().AsReadOnly(); }
- }
-
-
-
- public string Name
- {
- get { return name; }
- }
-
-
-
- public abstract bool Started { get; }
-
-
-
- public void Initialize()
- {
- lock (initalizeLock)
- {
- if (!initialized)
- {
-
- CreateStateObjects();
- if (initialState == null)
- throw new StateEngineException("Must set an initial state for the state machine! In " + name);
- initialized = true;
- }
- }
- }
-
-
-
- public StateNameKind LogNameKind
- {
- get { return MainStateMachine.logNameKind; }
- set { MainStateMachine.logNameKind = value; }
- }
- private StateMachine MainStateMachine
- {
- get
- {
- if (mainStateMachine == null)
- {
- if (parentStateMachine != null)
- {
- mainStateMachine = parentStateMachine;
- while (mainStateMachine.parentStateMachine != null)
- mainStateMachine = mainStateMachine.parentStateMachine;
- }
- else
- mainStateMachine = this;
- }
- return mainStateMachine;
- }
- }
- #endregion
- #region Internal Properties
-
-
-
-
- internal StateMachine ParentStateMachine
- {
- get { return parentStateMachine; }
- set { parentStateMachine = value; }
- }
-
-
-
- internal bool Initialized
- {
- get
- {
- lock (initalizeLock)
- {
- return initialized;
- }
- }
- }
-
-
-
-
- public void SetAndMergeTypeContainer(StateTypeContainer newStateTypeContainer)
- {
- newStateTypeContainer.Register(stateTypeContainer);
- stateTypeContainer = newStateTypeContainer;
- }
- #endregion
- #region Internal Methods
-
-
-
-
-
- internal void EnterInitialState(Transition sourceTransition, ref Transition transition)
- {
- StateEntry stateEntry = null;
- if (sourceTransition == null)
- {
- stateEntry = new StateEntry(new Transition(null, BasicTransitionType.Init),
- this.initialState.FactoryName,
- HistoryType.None);
- }
- else
- {
- stateEntry = new StateEntry(sourceTransition, this.initialState.FactoryName, HistoryType.None);
- }
- PerformStateChange(this.initialState, stateEntry, ref transition);
- if (transition != null)
- this.HandleTransition(ref transition);
- }
-
-
-
-
-
-
- internal void EnterState(StateEntry stateEntry, ref Transition transition)
- {
- switch (stateEntry.HistoryType)
- {
-
- case HistoryType.None:
- {
- EnterInitialState(stateEntry.SourceTransition, ref transition);
- break;
- }
-
- case HistoryType.Shallow:
- {
- if (currentState != null)
- {
- var initEntry = new StateEntry(stateEntry.SourceTransition,
- initialState.FactoryName,
- HistoryType.None);
- PerformStateChange(currentState, initEntry, ref transition);
- }
- else
- EnterInitialState(stateEntry.SourceTransition, ref transition);
- break;
- }
-
- case HistoryType.Deep:
- {
- if (currentState != null)
- {
- var InitEntry = new StateEntry(stateEntry.SourceTransition,
- initialState.FactoryName,
- HistoryType.Deep);
- PerformStateChange(currentState, InitEntry, ref transition);
- }
- else
- EnterInitialState(stateEntry.SourceTransition, ref transition);
- break;
- }
-
- case HistoryType.Explicit:
- {
- var explicitTransition = stateEntry.SourceTransition;
- this.HandleTransition(ref explicitTransition);
- if (explicitTransition != null)
- transition = explicitTransition;
- break;
- }
- }
- }
-
-
-
-
- internal void ExitState()
- {
- lock (this)
- {
- if (currentState != null)
- currentState.PerformExit();
-
- lock (timerWrapperListLock)
- {
- if ((debugLogger != null) && debugLogger.IsActive(DebugLogLevel.Maximized))
- debugLogger.Add("Disabling all TimerWrappers", DebugLogLevel.Maximized);
- var tempTimerWrapperList = new List<TimerWrapper>(timerWrapperList);
- foreach (var wrapper in tempTimerWrapperList)
- wrapper.Disable();
- }
- }
- }
-
-
-
-
-
- internal virtual void HandleEvent(StateEngineEvent stateEngineEvent, ref Transition transition)
- {
- currentState.IncomingEvent(stateEngineEvent, ref transition);
- if (transition != null)
- this.HandleTransition(ref transition);
- }
-
-
-
-
-
-
-
-
-
-
- internal void HandleTransition(ref Transition transition)
- {
- var explicitTransition = transition as ExplicitTransition;
- bool transitionHandled;
- if (disposed)
- return;
- do
- {
- transitionHandled = false;
-
-
- if (explicitTransition == null)
- {
-
-
- var entry = StateTransitionLookup.GetNextState(currentState.FactoryName, transition);
- if ((entry != null) && !(currentState is FinalState))
- {
- transitionHandled = true;
- transition = null;
- var St = this.GetState(entry.TargetStateFactoryName);
- if (St != null)
- PerformStateChange(St, entry, ref transition);
- }
-
-
- }
-
-
- else
- {
- State nextState = null;
-
-
- foreach (var state in createdStates)
- {
- if (state.Value.LookupState(explicitTransition.TargetStateFactoryName))
- {
- nextState = state.Value;
- break;
- }
- }
-
- if (nextState != null)
- {
- var entry = new StateEntry(explicitTransition, nextState.FactoryName, HistoryType.Explicit);
- transition = null;
- transitionHandled = true;
- PerformStateChange(nextState, entry, ref transition);
- }
-
-
- }
- } while (transitionHandled && transition != null && !disposed);
- }
-
-
-
- internal virtual void ClearPendingEvents()
- {
- if (parentStateMachine != null)
- parentStateMachine.ClearPendingEvents();
- }
-
-
-
- internal void FireFinalStateEntered()
- {
- if (OnFinalStateEntered != null)
- OnFinalStateEntered(this, EventArgs.Empty);
- }
- internal void SetDebugLogger(IDebugLogger debugLogger, object logCategory)
- {
- this.debugLogger = debugLogger;
- this.logCategory = logCategory;
- }
- #endregion
- #region IDisposable Members
-
-
-
-
-
- protected virtual void Dispose(bool disposing)
- {
- if (!disposed)
- {
- disposed = true;
- if (Started && (debugLogger != null) && debugLogger.IsActive(logCategory))
- debugLogger.Add("--------- Stopping State machine (Dispose)---------", logCategory);
- if ((currentState != null) && currentState.Active)
- {
- currentState.PerformExit();
- currentState = null;
- }
- if (disposing)
- {
-
- lock (timerWrapperListLock)
- {
- List<TimerWrapper> tempTimerWrapperList = new List<TimerWrapper>(timerWrapperList);
- foreach (TimerWrapper timerWrapper in tempTimerWrapperList)
- {
- timerWrapper.Dispose();
- }
- timerWrapperList.Clear();
- }
- createdStates.Values.ForEach(x => x.Dispose());
- createdStates.Clear();
- timerOnDisableEventHandler -= timer_OnDisable;
- timerOnEnableEventHandler -= timer_OnEnable;
- }
- }
- }
-
-
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- #endregion
- #region Timer methods
-
-
-
-
-
- public void ActivateTimer(Wayne.Lib.StateEngine.Timer timer)
- {
- timer.OnEnable += timerOnEnableEventHandler;
- timer.OnDisable += timerOnDisableEventHandler;
- timer.Enable();
- if ((debugLogger != null) && debugLogger.IsActive(DebugLogLevel.Maximized))
- debugLogger.Add("Activating timer for " + timer.ToString(), DebugLogLevel.Maximized);
- }
-
-
-
-
-
-
- void timer_OnDisable(object sender, EventArgs e)
- {
- Timer stateEngineTimer = (Timer)sender;
- if ((debugLogger != null) && debugLogger.IsActive(DebugLogLevel.Maximized))
- debugLogger.Add("Disabling StateEngineTimer " + stateEngineTimer.ToString(), DebugLogLevel.Maximized);
- lock (timerWrapperListLock)
- {
-
- TimerWrapper foundTimerWrapper = null;
- foreach (TimerWrapper wrapper in timerWrapperList)
- {
- if (wrapper.StateEngineTimer == stateEngineTimer)
- {
- foundTimerWrapper = wrapper;
- break;
- }
- }
- if (foundTimerWrapper != null)
- {
- foundTimerWrapper.StateEngineTimer = null;
- if (!TimerWrapperCaching)
- {
- foundTimerWrapper.Dispose();
- timerWrapperList.Remove(foundTimerWrapper);
- }
-
-
-
-
- }
- }
- }
-
-
-
-
-
- void timer_OnEnable(object sender, EventArgs e)
- {
- Timer stateEngineTimer = (Timer)sender;
- if ((debugLogger != null) && (debugLogger.IsActive(DebugLogLevel.Maximized)))
- debugLogger.Add("Enabling StateEngineTimer for " + stateEngineTimer.ToString(), DebugLogLevel.Maximized);
- lock (timerWrapperListLock)
- {
- TimerWrapper wrapper = GetTimerWrapper(stateEngineTimer);
- wrapper.Enable();
- }
- }
-
-
-
-
-
-
- private TimerWrapper GetTimerWrapper(Timer stateEngineTimer)
- {
- TimerWrapper wrapper = null;
- lock (timerWrapperListLock)
- {
-
- foreach (TimerWrapper tempWrapper in timerWrapperList)
- {
- if (tempWrapper.StateEngineTimer == stateEngineTimer)
- {
- wrapper = tempWrapper;
- break;
- }
- }
-
- if (wrapper == null)
- {
- foreach (TimerWrapper tempWrapper in timerWrapperList)
- {
- if (tempWrapper.StateEngineTimer == null)
- {
- wrapper = tempWrapper;
- wrapper.StateEngineTimer = stateEngineTimer;
- break;
- }
- }
- }
-
- if (wrapper == null)
- {
- wrapper = new TimerWrapper(TimerFired);
- wrapper.StateEngineTimer = stateEngineTimer;
- timerWrapperList.Add(wrapper);
- }
- }
- return wrapper;
- }
-
-
-
-
- void TimerFired(object state)
- {
- TimerWrapper timerWrapper = (TimerWrapper)state;
- StateEngineEvent stateEngineEvent = null;
- lock (timerWrapperListLock)
- {
- Timer stateEngineTimer = timerWrapper.StateEngineTimer;
- if (stateEngineTimer != null)
- {
- if ((debugLogger != null) && debugLogger.IsActive(DebugLogLevel.Maximized))
- debugLogger.Add("StateEngineTimer Fired " + stateEngineTimer.ToString(), DebugLogLevel.Maximized);
-
- if (!stateEngineTimer.IsPeriodic)
- {
- stateEngineTimer.Disable();
- }
- stateEngineEvent = new TimerEvent(stateEngineTimer.UserToken, stateEngineTimer.EventType);
- }
- }
- if (stateEngineEvent != null)
- IncomingEvent(stateEngineEvent);
- }
-
-
-
- private void CheckAndRemoveTimersForCurrentState()
- {
-
- lock (timerWrapperListLock)
- {
- List<TimerWrapper> tempTimerWrapperList = new List<TimerWrapper>(timerWrapperList);
- foreach (TimerWrapper timerWrapper in tempTimerWrapperList)
- {
- if (timerWrapper.StateEngineTimer != null)
- {
- if (timerWrapper.StateEngineTimer.OwnerState == currentState)
- {
- if (timerWrapper.StateEngineTimer.ClearAtStateExit)
- {
- if ((debugLogger != null) && debugLogger.IsActive(DebugLogLevel.Maximized))
- debugLogger.Add("!IsPeriodic: Disabling timer because of state change " + timerWrapper.StateEngineTimer.ToString(), DebugLogLevel.Maximized);
- timerWrapper.StateEngineTimer.Disable();
- }
- }
- }
- }
- }
- }
- #endregion
- #region Static Methods
-
-
-
-
-
-
-
-
- public static StateMachine Create(string name, IDebugLogger debugLogger, object logCategory)
- {
- return Create(name, StateMachineType.Threaded, debugLogger, logCategory);
- }
-
-
-
-
-
-
-
-
- public static StateMachine Create(string name, StateMachineType stateMachineType, IDebugLogger debugLogger, object logCategory)
- {
- switch (stateMachineType)
- {
- case StateMachineType.Threaded: return new ThreadedRootStateMachine(name, debugLogger, logCategory);
- case StateMachineType.Synchronous: return new SynchronousRootStateMachine(name, debugLogger, logCategory);
- default: throw new NotImplementedException("This statemachine type is not yet implemented.");
- }
- }
- #endregion
- }
- }
|