export interface StateMachineConfig < StateEnum , EventEnum > { initial ? : StateEnum ; events : any ; debug ? : boolean ; } export class StateMachine < StateEnum , EventEnum > { private inital : StateEnum ; private state : StateEnum ; private asyncing : boolean ; private eventMap : { [ from ] : { [ event ] : StateEnum ; } ; } = { } ; private stateMap : { [ from ] : [ string ] ; } = { } ; private eventCb : { before : { [ event ] : Function ; } ; after : { [ event ] : Function ; } ; } = { before : { } , after : { } } ; private stateCb : { enter : { [ event ] : Function ; } ; leave : { [ event ] : Function ; } ; } = { enter : { } , leave : { } } ; private errorCb : Function ; private debug : boolean ; constructor ( cfg ) { console . log ( cfg ) ; this . debug = cfg . debug || false ; this . inital = cfg . initial ; this . state = cfg . initial ; for ( let i = 0 ; i < cfg . events . length ; i += 1 ) { let froms = ( cfg . events [ i ] . from instanceof Array ) ? cfg . events [ i ] . from : [ cfg . events [ i ] . from ] ; for ( let j = 0 ; j < froms . length ; j += 1 ) { this . eventMap [ '' + froms [ j ] ] = this . eventMap [ '' + froms [ j ] ] || { } ; this . eventMap [ '' + froms [ j ] ] [ '' + cfg . events [ i ] . name ] = cfg . events [ i ] . to ; } } } input ( event ) { let func ; if ( this . debug ) { console . log ( 'Event: ' , event , 'Before: ' , this . state ) ; } if ( func = this . eventCb . before [ '' + event ] ) { func ( ) ; } if ( this . eventMap [ '' + this . state ] [ '' + event ] === undefined ) { this . error ( this . state , event ) ; return false ; } let prevState = this . state ; this . state = this . eventMap [ '' + prevState ] [ '' + event ] ; if ( func = this . stateCb . enter [ '' + this . state ] ) { func ( ) ; } if ( func = this . stateCb . leave [ '' + prevState ] ) { func ( ) ; } if ( func = this . eventCb . after [ '' + event ] ) { func ( ) ; } if ( this . debug ) { console . log ( 'Event: ' , event , 'After: ' , this . state ) ; } return true ; } canInput ( event ) { return true ; } go ( state ) { let func ; return true ; } canGo ( state ) { return true ; } is ( state ) { return state == this . state ; } current ( ) { return this . state ; } reset ( ) { this . state = this . inital ; } onBefore ( event , cb ) { this . eventCb . before [ '' + event ] = cb ; } onAfter ( event , cb ) { this . eventCb . after [ '' + event ] = cb ; } onEnter ( state , cb ) { this . stateCb . enter [ '' + state ] = cb ; } onLeave ( state , cb ) { this . stateCb . leave [ '' + state ] = cb ; } onError ( cb ) { this . errorCb = cb ; } error ( from , event , to ? ) { let func ; if ( func = this . errorCb ) { func ( from , event ) ; } console . log ( "error when transition from " , from , " " , event ) ; } }