using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Collections.Generic; namespace SilverlightGame { public class StateChangeInfo { public delegate void StateFunction(); public StateFunction enterState = null; public StateFunction exitState = null; public StateChangeInfo(StateFunction enterState, StateFunction exitState) { this.enterState = enterState; this.exitState = exitState; } } public static class States { public static string START_STATE = "start"; public static string END_STATE = "end"; } public class StateManager { protected static StateManager instance = null; // the name of the current state protected string currentState = string.Empty; // the name of the new state protected string newState = string.Empty; // a list of functions to be called when a state is changed Dictionary<string, List<StateChangeInfo>> stateChangeMap = new Dictionary<string,List<StateChangeInfo>>(); // true if subsequent calles to SetState are queued (to allow state change function to be called in the correct order) bool stateChangeLocked; // a list of pending state changed List<string> pendingStateChangeRequests = new List<string>(); // a list of new state changes List<string> newStateChangeRequests = new List<string>(); public static StateManager Instance { get { if (instance == null) instance = new StateManager(); return instance; } } public string CurrentState { get { return currentState; } } protected StateManager() { } public void startupStateManager() { setState(States.START_STATE); } public void shutdown() { endCurrentState(); } public void endCurrentState() { setState(States.END_STATE); } protected void updateStates() { // we can only change the states if stateChangeLocked is false (i.e. the state change // isn't called from one of the enter or exit state functions) if (!stateChangeLocked) { // set the lock stateChangeLocked = true; // push all our new state changes onto the pending state change list foreach (string info in newStateChangeRequests) pendingStateChangeRequests.Add(info); newStateChangeRequests.Clear(); // now process the pending state changes while (pendingStateChangeRequests.Count != 0) { foreach (string stateChangeRequest in pendingStateChangeRequests) { if (!stateChangeRequest.Equals(currentState)) { // call the exit function for all state listeners that are in the current state if (stateChangeMap.ContainsKey(currentState)) { foreach (StateChangeInfo info in stateChangeMap[currentState]) { info.exitState(); } } if (!stateChangeRequest.Equals(States.END_STATE)) { if (stateChangeMap.ContainsKey(stateChangeRequest)) { foreach (StateChangeInfo info in stateChangeMap[stateChangeRequest]) { info.enterState(); } } } } currentState = stateChangeRequest; } // all current pending state changes have been processed, so clear the list pendingStateChangeRequests.Clear(); // push all our new state changes onto the pending state change list foreach (string info in newStateChangeRequests) pendingStateChangeRequests.Add(info); newStateChangeRequests.Clear(); } stateChangeLocked = false; } } public void setState(string newState) { // we have to jump through some hoops to ensure that all state change requests are // processed in order because it is possible to change the state from within // an enter or exit state function. To do this we add all state requests to // newStateChangeRequests, lock the state change loop, copy all requests // from newStateChangeRequests to pendingStateChangeRequests and then // process the state changes in pendingStateChangeRequests. // add our requested state change to the newStateChangeRequests vector newStateChangeRequests.Add(newState); updateStates(); } public void registerStateChange(string state, StateChangeInfo.StateFunction enterState, StateChangeInfo.StateFunction exitState) { if (!state.Equals(States.END_STATE)) { if (!isRegisteredState(state)) stateChangeMap.Add(state, new List<StateChangeInfo>()); stateChangeMap[state].Add(new StateChangeInfo(enterState, exitState)); } } public bool isRegisteredState(string state) { return stateChangeMap.ContainsKey(state); } } }