internal static List <InternalState <TInternalState> > FindAllStates( IReadOnlyDictionary <InternalState <TInternalState>, InternalState <TInternalState> > relations, InternalState <TInternalState> childState) { if (childState == null) { throw new ArgumentNullException("childState", "When trying to find a parent state the childState cannot be null!"); } var _nextStates = new Stack <InternalState <TInternalState> >(); // Find the list of states that represents every state that surround the state we are trying to transition to InternalState <TInternalState> currentState = childState; _nextStates.Push(childState); while (relations.ContainsKey(currentState)) { var t = relations[currentState]; _nextStates.Push(t); currentState = t; } return(_nextStates.ToList()); }
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); } }
internal MachineState( Dictionary <InternalState <TInternalState>, InternalState <TInternalState> > stateHistories , TInternalState state , InternalState <TInternalState> currentState) { _stateHistories = stateHistories; _currentInternalState = state; _currentState = currentState; }
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 static InternalState <TInternalState> FindParentState( IReadOnlyDictionary <InternalState <TInternalState>, InternalState <TInternalState> > relations, InternalState <TInternalState> childState) { if (relations.ContainsKey(childState)) { return(relations[childState]); } else { return(null); } }
void IMachineState <TInternalState> .AddInitialHistory(InternalState <TInternalState> parentState, InternalState <TInternalState> initialState) { if (parentState == null) { throw new ArgumentNullException("parentState", "The Parent state cannot be null when trying to Add initial histories"); } if (initialState == null) { throw new ArgumentNullException("initialState", "The Initial State cannot be null when trying to Add initial histories"); } _stateHistories[parentState] = initialState; }
/// <summary> /// Runs through all the current states - and updates the state histories to the current ones. /// </summary> private static void UpdateStateHistories <TInternalState>(IMachineState <TInternalState> internalState, IReadOnlyDictionary <InternalState <TInternalState>, InternalState <TInternalState> > parentStates, InternalState <TInternalState> nextState) { foreach (var state in Misc <TInternalState> .FindAllStates(parentStates, nextState)) { var parentState = Misc <TInternalState> .FindParentState(parentStates, state); if ((parentState != null) && internalState.StateHistory.ContainsKey(parentState)) { internalState.StateHistory[parentState] = state; } } }
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); }
void IMachineState <TInternalState> .ChangeState(InternalState <TInternalState> newState) { _currentState = newState; }
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); }