package com.zachklipp.captivate.state_machine;
import com.zachklipp.captivate.util.*;
public class StateMachine extends Observable<TransitionEvent>
{
private SetMap<State> mTransitionMatrix;
private State mCurrentState;
public StateMachine(State initialState, State[][] transitionMatrix)
{
mTransitionMatrix = new SetMap<State>(transitionMatrix);
mCurrentState = initialState;
validatePostConstructor();
}
public StateMachine(String initialStateName, State[][] transitionMatrix)
{
mTransitionMatrix = new SetMap<State>(transitionMatrix);
State initialState = findStateByName(initialStateName);
mCurrentState = initialState;
validatePostConstructor();
}
private void validatePostConstructor()
{
if (mCurrentState == null || mTransitionMatrix.size() == 0)
{
throw new IllegalArgumentException("Non-null initial state and non-empty transitionMatrix required");
}
}
public State getCurrentState()
{
return mCurrentState;
}
public State findStateByName(String name)
{
for (State state : mTransitionMatrix.getKeys())
{
if (name.equals(state.getName()))
return state;
}
return null;
}
/*
* Set the current state to state if allowed, and update
* observers, passing the old state as the event.
*/
public void transitionTo(State state)
{
assert(state != null);
if (!mCurrentState.equals(state))
{
if (canTransition(mCurrentState, state))
{
TransitionEvent event = new TransitionEvent(mCurrentState, state);
mCurrentState = state;
notifyObservers(event);
}
else
{
throw new InvalidTransitionException(mCurrentState, state);
}
}
}
private boolean canTransition(State fromState, State toState)
{
return mTransitionMatrix.get(fromState).contains(toState);
}
}