/* * @Author: 陶秋峰 * @Date: 2015-10-23 10:27:13 * @Last Modified by: 陶秋峰 * @Last Modified time: 2015-11-21 16:22:06 * @CopyRight */ import Base from './base'; import Feedback from './defines/feedback'; import OAV from './defines/oav'; import {Hash} from './interfaces'; import {uuid} from './lang'; import * as lang from './lang'; import Promise from './promise'; import * as nools from 'nools'; import * as StateMachine from 'state-machine'; import component from './api/component'; import page from './api/page'; function start_nools(me, fsm: StateMachine.StateMachine, session: nools.Session) { let last: Promise<{}>; // let StateEvent: mmstudio.ai.StateEvent = flow.getDefined('StateEvent'); // let feedback: mmstudio.ai.feedback = flow.getDefined('feedback'); // let OAV: mmstudio.ai.OAV = flow.getDefined('oav'); return function(is_guard: boolean, action: string, args: any[]){ // 鼠标事件属性会在异步时被清除掉,在这里修改下属性名称并保存 args.forEach(function(e) { e && e.currentTarget && (e.current_target = e.currentTarget); }); let fire = function() { return new Promise((resolve, reject) => { session.focus(action); session.assert(args); // 事件参数 let fd; if (is_guard) { fd = new Feedback(); session.assert(fd); } try{ session.match((err: any) => { session.retract(args); // session.focus('main'); // set back to default group err && console.error(err); if (fd) { session.retract(fd); (fd.flag && !err) ? resolve(fd.msg) : reject(fd.msg); }else{ err ? reject(err) : resolve({}); } }); } catch (e) { session.focus('main'); // set back to default group console.error(e); if (fd) { session.retract(fd); reject(fd.msg); }else{ reject(e); } } }); }; if (last/* && !last.isFulfilled()*/) { last = last.then(fire); } else { last = fire(); } return last; }; } export interface IFsmState{ transitions: StateMachine.StateMachineEventDef[]; events?: Hash; states?: Hash<{// [guard exit transition entry do done] guard: string[]; exit: string[]; entry: string[]; do: string[]; done: string[]; }> } export interface iscope{ flow: nools.Session; me: Base; fsm: StateMachine.StateMachine; mm: any; } function to_arr(arr_like, start){ return Array.prototype.slice.call(arr_like, start); } export default function ai(me: Base, rules, status: IFsmState, is_component: boolean){ let events = status.events || {}; let transitions = status.transitions || []; let states = status.states || {}; let fsm = StateMachine.create({ initial: { state: 'none', defer: true }, // 'final': final, events: transitions, error: function(name, from, to, args, error, msg, e){ console.error(e || msg); }, callbacks: { // onbeforeevent: function(event, from, to) { // // return false; // }, onafterevent: function(event, from, to) { // 4 // console.log('onafterevent..........................'); // console.info(event, from, to); /** * 1.状态自转移 进入--》离开状态都要触发。 停止do操作 2.内部转移 持续执行do操作。 例如:计数,导航 */ var fire_all = function(state){ state && state.forEach(function(action: string){ fire(false, action, args); }); } let state_from = states[from] || { exit: [] }; let state_to = states[to] || { entry: [], 'do': [], done: [] }; let args = to_arr(arguments, 3); fire_all(state_from.exit); // fire('transition', event, from, to, args); fire_all(events[event]); fire_all(state_to.entry); fire_all(state_to['do']); fire_all(state_to.done); }, onleavestate: function(event, from, to) { // 1 let state = states[from]; if(!state){ return; } let actions = state.guard; if(!actions || actions.length === 0){ return; } let args = to_arr(arguments, 3); let ds = actions.map(function(action: string){ return fire(true, action, args); }); Promise.all(ds).then(function() { fsm.transition(); },function(){ fsm.transition.cancel(); }); return StateMachine.ASYNC; // }, // onenterstate: function(event, from, to) { // // 2 // }, // onchangestate: function(event, from, to) { // // 3 } } }); fsm.events = transitions; let defines = { feedback: Feedback, OAV: OAV }; let scope: iscope = lang.mixin({ me: me, fsm: fsm, flow: null, mm: null }, defines); scope.mm = (is_component? component: page)(scope); let options = { name: uuid(), 'define': defines, scope: scope }; let flow: nools.FlowContainer; if(lang.is_string(rules)){ flow = nools.compile(rules, options); }else{ flow = rules(options); } let session = flow.getSession(); nools.deleteFlow(flow.name); scope.flow = session; let fire = start_nools(me, fsm, session); fsm.startup(); return fsm; };