private static void Dispatch <TInternalState, TEvent>(TEvent evnt , IMachineState <TInternalState> internalState , InternalState <TInternalState> currentState , IReadOnlyDictionary <InternalState <TInternalState>, InternalState <TInternalState> > relations , IEnumerable <Func <object, object> > eventInterceptors , MachineConfiguration <TInternalState> config , bool outerTransitionsTakePrecedence , Func <string, InternalState <TInternalState> > lookup) { var currentStates = Misc <TInternalState> .FindAllStates(relations, currentState); if (!outerTransitionsTakePrecedence) { currentStates.Reverse(); } var nextState = DispatchToStates(evnt, internalState, currentStates, eventInterceptors, config, lookup); if (nextState != null && nextState != currentStates.Last()) { nextState = TransitionTo((object)evnt, internalState, relations, nextState, eventInterceptors, false, config, lookup); } if (nextState != null) { UpdateStateHistories(internalState, relations, nextState); } }
private static InternalState <TInternalState> TransitionTo <TInternalState>( object evnt , IMachineState <TInternalState> machineState , IReadOnlyDictionary <InternalState <TInternalState>, InternalState <TInternalState> > relations , InternalState <TInternalState> transitionToState , IEnumerable <Func <object, object> > eventInterceptors , bool exitInnerStatesFirst , MachineConfiguration <TInternalState> config , Func <string, InternalState <TInternalState> > lookup) { config.Logger(string.Format("SM:{0}:{1} = State: {2} -> {3} on ^{4} = '{5}'" , config.Name , config.GetUniqueId(machineState.CurrentInternalState) , machineState.CurrentState.Name , transitionToState.Name , evnt.GetType().Name , config.LogEvents(evnt))); var _currentStates = Misc <TInternalState> .FindAllStates(relations, machineState.CurrentState); var _nextStates = Misc <TInternalState> .FindAllStates(relations, transitionToState); while (machineState.StateHistory.ContainsKey(transitionToState)) { var nextTransitionToState = machineState.StateHistory[transitionToState]; transitionToState = nextTransitionToState; _nextStates.Add(nextTransitionToState); } var entryConditionsToRun = _nextStates.Except(_currentStates); var exitConditionsToRun = _currentStates.Except(_nextStates); if (exitInnerStatesFirst) { entryConditionsToRun.Reverse(); exitConditionsToRun.Reverse(); } // Dispatch and do not transition... var newState = DispatchToStates(new Events.ExitEvent(), machineState, exitConditionsToRun, eventInterceptors, config, lookup); machineState.ChangeState(_nextStates.Last()); // Dispath entry event - transition if neccesary and do not transition... newState = DispatchToStates(new Events.EntryEvent(), machineState, entryConditionsToRun, eventInterceptors, config, lookup); if (newState != null) { transitionToState = TransitionTo(evnt, machineState, relations, newState, eventInterceptors, exitInnerStatesFirst, config, lookup); } return(transitionToState); }
internal MachineDefinition( IReadOnlyList <InternalState <TInternalState> > registeredStates, IReadOnlyDictionary <string, string> parentStates, IReadOnlyList <Func <object, object> > eventInterceptors, MachineConfiguration <TInternalState> config, IState initialState, Dictionary <BuilderState <TInternalState>, BuilderState <TInternalState> > stateHistories) { if (registeredStates == null) { throw new ArgumentNullException(nameof(registeredStates)); } if (parentStates == null) { throw new ArgumentNullException(nameof(parentStates)); } if (eventInterceptors == null) { throw new ArgumentNullException(nameof(eventInterceptors)); } if (initialState == null) { throw new ArgumentNullException(nameof(initialState)); } if (stateHistories == null) { throw new ArgumentNullException(nameof(stateHistories)); } _log = config.Logger; RegisteredState = registeredStates; EventInterceptors = eventInterceptors; Config = config; InitialState = LookupRegisteredState(initialState.Name); StateHistories = stateHistories.ToDictionary(x => LookupRegisteredState(x.Key.Name), x => LookupRegisteredState(x.Value.Name));; ParentStates = parentStates.ToDictionary( x => LookupRegisteredState(x.Key), x => LookupRegisteredState(x.Value)); Log(registeredStates); }
private static InternalState <TInternalState> Execute <TInternalState, TEvent>(TEvent evnt, IMachineState <TInternalState> internalState, MachineConfiguration <TInternalState> config, InternalState <TInternalState> finalTransitionState, InternalState <TInternalState> currentState, Func <string, InternalState <TInternalState> > lookup) { var handler = currentState.Handlers[evnt.GetType()]; Action <string> log = str => config.Logger($"SM:{config.Name}:{config.GetUniqueId(internalState.CurrentInternalState)} = State: {currentState.Name} - {str}"); foreach (var action in handler.TransistionDefinitions) { if (action.GuardCondition(internalState.CurrentInternalState, evnt)) { action.Action?.Invoke(internalState.CurrentInternalState, evnt, log); if (action.TransitionTo != null) { finalTransitionState = finalTransitionState ?? lookup(action.TransitionTo); } } } return(finalTransitionState); }
private static InternalState <TInternalState> DispatchToStates <TInternalState, TEvent>(TEvent evnt , IMachineState <TInternalState> internalState , IEnumerable <InternalState <TInternalState> > statesToDispatchTo , IEnumerable <Func <object, object> > eventInterceptors , MachineConfiguration <TInternalState> config , Func <string, InternalState <TInternalState> > lookup) { TEvent evntToDispatch = ExecuteInterceptorsForEvent(evnt, eventInterceptors); if (evntToDispatch == null) { // Do not dispatch a null event! return(null); } InternalState <TInternalState> finalTransitionState = null; Type eventType = evnt.GetType(); foreach (var currentState in statesToDispatchTo) { if (currentState.Handlers.ContainsKey(eventType)) { finalTransitionState = Execute(evnt, internalState, config, finalTransitionState, currentState, lookup); } else if (eventType != typeof(Events.EntryEvent) & eventType != typeof(Events.ExitEvent)) { if (currentState.Handlers.ContainsKey(typeof(Events.DefaultEvent))) { finalTransitionState = Execute(new Events.DefaultEvent(), internalState, config, finalTransitionState, currentState, lookup); } } if (eventType != typeof(Events.EntryEvent) & eventType != typeof(Events.ExitEvent)) { // Always run an AnyEvent() - if (currentState.Handlers.ContainsKey(typeof(Events.AnyEvent))) { finalTransitionState = Execute(new Events.AnyEvent(), internalState, config, finalTransitionState, currentState, lookup); } } } return(finalTransitionState); }