import { AbstractState } from "./AbstractState" ; import * as _ from "lodash" ; import { AbstractStateMachineInput } from "./AbstractStateMachineInput" ; import { BaseEvent , BaseListener , BaseObject } from "@projectstorm/react-core" ; export interface StateMachineListener extends BaseListener < StateMachine > { stateChanged ( event ) ; } export class StateMachine extends BaseObject < StateMachineListener > { inputs : { [ name ] : AbstractStateMachineInput ; } ; states : { [ name ] : AbstractState ; } ; state : AbstractState ; constructor ( ) { super ( ) ; this . inputs = { } ; this . states = { } ; this . state = null ; } addState ( state ) { if ( this . states [ state . getName ( ) ] ) { throw "A state with name: " + state . getName ( ) + " is already registered" ; } this . states [ state . getName ( ) ] = state ; } removeInput ( type , fire = true ) { if ( ! this . inputs [ type ] ) { return ; } delete this . inputs [ type ] ; if ( fire ) { this . process ( ) ; } } addInput ( input , fire = true ) { this . inputs [ input . name ] = input ; if ( fire ) { this . process ( ) ; } return input ; } getInput ( name ) { return _ . find ( this . inputs , { name : name } ) ; } clearState ( ) { if ( this . state ) { this . state . deactivated ( this ) ; } else { return ; } this . state = null ; this . fireStateChanged ( ) ; } fireStateChanged ( ) { this . iterateListeners ( "state changed" , ( listener , event ) => { if ( listener . stateChanged ) { listener . stateChanged ( { ... event , state : this . state } ) ; } } ) ; } setState ( state ) { if ( this . state && state ) { if ( this . state . name !== state . name ) { this . state . deactivated ( this ) ; this . state = state ; state . activated ( this ) ; this . fireStateChanged ( ) ; } } else { this . state = state ; state . activated ( this ) ; this . fireStateChanged ( ) ; } } process ( ) { let possibleReactions = _ . map ( _ . filter ( this . states , state => { return state . shouldStateActivate ( this ) ; } ) , state => { return state . getName ( ) ; } ) ; if ( possibleReactions . length === 0 ) { this . clearState ( ) ; } else if ( possibleReactions . length > 0 ) { this . setState ( this . states [ possibleReactions [ 0 ] ] ) ; } } }