using System; using System.Collections.Generic; using System.Linq; namespace Wayne.Lib.StateEngine { public static class StateTransitionLookupAnalyze { #region Method: GetNextStateName /// <summary> /// /// </summary> /// <param name="stateMachine"></param> /// <param name="sourceStateFactoryName"></param> /// <param name="transitionType"></param> /// <param name="historyType"></param> /// <param name="fromAnyState"></param> /// <returns></returns> public static string GetNextStateName(this StateMachine stateMachine, string sourceStateFactoryName, object transitionType, out HistoryType historyType, out bool fromAnyState) { if (sourceStateFactoryName != null && transitionType != null) { // Note: This routine should also work when stateMachine is null // (in this case: only look in the local lookupDictionary). foreach (StateMachine tempStateMachine in stateMachine.GetStateMachineHierarchy()) { StateLookupEntry entry; if (tempStateMachine.StateTransitionLookup.TryLookup(sourceStateFactoryName, transitionType, out entry)) { historyType = entry.HistoryType; fromAnyState = false; return entry.NextStateFactoryName; } if (tempStateMachine.StateTransitionLookup.TryLookup(AnyState.FactoryName, transitionType, out entry)) { historyType = entry.HistoryType; fromAnyState = true; return entry.NextStateFactoryName; } } } historyType = HistoryType.None; fromAnyState = false; return ""; } #endregion /// <summary> /// Returns a list of the source State names that is in the lookup table. /// </summary> /// <param name="stateTransitionLookup"></param> /// <param name="includeAnyStates">Should the AnyStates be included?</param> public static string[] GetSourceStateNameList(this StateTransitionLookup stateTransitionLookup, bool includeAnyStates) { IEnumerable<string> result = stateTransitionLookup.LookupTable.Keys; if (!includeAnyStates) result = result.Where(x => x != AnyState.FactoryName); // If AnyState is included, remove it. return result.ToArray(); } /// <summary> /// /// </summary> /// <param name="stateMachine"></param> /// <returns></returns> public static IEnumerable<StateMachine> GetStateMachineHierarchy(this StateMachine stateMachine) { StateMachine tempMachine = stateMachine; do { yield return tempMachine; tempMachine = tempMachine.ParentStateMachine; } while (tempMachine != null); } /// <summary> /// Returns a list of the AnyState-transition names (no duplicates). /// </summary> /// <returns></returns> public static string[] GetAnyStateTransitionNameList(this StateMachine stateMachine) { return stateMachine.GetStateMachineHierarchy() .SelectMany(sm => sm.StateTransitionLookup .GetTransitionsForState(AnyState.FactoryName) .Keys .Select(t => Transition.GetTransitionName(t))) .Distinct() .ToArray(); } /// <summary> /// Returns a dictionary of the transitions from a state (dictionary key) to a state (dictionary value). /// </summary> /// <param name="stateMachine"></param> /// <param name="sourceStateFactoryName"></param> /// <param name="includeAnyStates"></param> /// <returns></returns> public static Dictionary<string, string> GetStateTransitionsDict(this StateMachine stateMachine, string sourceStateFactoryName, bool includeAnyStates) { return stateMachine.StateTransitionLookup.GetTransitionsForState(sourceStateFactoryName) .ToDictionary(x => Transition.GetTransitionName(x.Key), x => x.Value.NextStateFactoryName); } /// <summary> /// Gets a list of all transitions. /// </summary> /// <param name="stateMachine"></param> /// <param name="includeAnyStates">Should the AnyState-transitions be included?</param> /// <returns></returns> public static TransitionInfo[] GetTransitionInfoArray(this StateMachine stateMachine, bool includeAnyStates) { return stateMachine.StateTransitionLookup.LookupTable .SelectMany(fromStatePair => fromStatePair.Value.Select(statePair => new TransitionInfo(fromStatePair.Key, Transition.GetTransitionName(statePair.Key), statePair.Value.NextStateFactoryName, statePair.Value.HistoryType))) .Where(x => includeAnyStates || x.FromStateFactoryName != AnyState.FactoryName) .ToArray(); } } }