exports.state_machine = function(def){
var state_machine = function(){};
state_machine.current_state = def.initial;
state_machine.transitioning = false;
var name, state_func;
for (name in def.states) {
state_func = function(ctx, clb){
var state_machine = arguments.callee.state_machine;
var old_state_name = state_machine.current_state;
var old_state = state_machine['to_'+old_state_name];
var new_state = arguments.callee;
var transition = old_state.transitions[new_state.state_name];
if (state_machine.transitioning) {
return false;
}
if (typeof(transition) == 'function') {
transition = transition(ctx);
}
if (transition) {
var s_steps = [], p_steps;
s_steps.push(function(ctx, clb){
state_machine.transitioning = true;
clb(ctx);
});
p_steps = [];
if (old_state.before_leave)
p_steps.push(old_state.before_leave);
if (new_state.before_enter)
p_steps.push(new_state.before_enter);
if (p_steps.length > 0)
s_steps.push(exports.stacks.parallel(p_steps));
p_steps = [];
if (old_state.leave)
p_steps.push(old_state.leave);
if (new_state.enter)
p_steps.push(new_state.enter);
if (p_steps.length > 0)
s_steps.push(exports.stacks.parallel(p_steps));
s_steps.push(function(ctx, clb){
state_machine.current_state = new_state.state_name;
clb(ctx);
});
p_steps = [];
if (old_state.after_leave)
p_steps.push(old_state.after_leave);
if (new_state.after_enter)
p_steps.push(new_state.after_enter);
if (p_steps.length > 0)
s_steps.push(exports.stacks.parallel(p_steps));
s_steps.push(function(ctx, clb){
state_machine.transitioning = false;
clb(ctx);
});
exports.stacks.serial(s_steps)(ctx, clb);
return true;
} else {
return false;
}
};
state_func.state_name = name;
state_func.state_machine = state_machine;
state_func.before_enter = def.states[name].before_enter;
state_func.before_leave = def.states[name].before_leave;
state_func.enter = def.states[name].enter;
state_func.leave = def.states[name].leave;
state_func.after_enter = def.states[name].after_enter;
state_func.after_leave = def.states[name].after_leave;
state_func.transitions = def.transitions[name];
state_machine['to_'+name] = state_func;
}
return state_machine;
};