import { sp } from "cc";
import GFSMBase, { GFSMProcessEnum, GFSMProcessInfo, GFSMProcessMode } from "./GFSMBase";
import GObject from "../GObject";
import { JNFrameInfo } from "../../../../../extensions/ngame/assets/ngame/sync/frame/JNSyncFrame";


//动画流程信息
export interface GFSMProcessAnimInfo extends GFSMProcessInfo{
    //动画名称
    animName:string;
    //是否循环播放
    isLoop?:boolean;
    //与下一个动作的融合值
    mixs?:number[];
    //播放的轨道
    track?:sp.spine.TrackEntry;
    //条件跳转
    ifTo?:(() => boolean)[];
}

//动画状态机基类
export abstract class GFSMAnimBase extends GFSMBase{

    //轨道的索引
    trackIndex:number;

    //动画Root
    spine:sp.Skeleton;

    events:{[key:string]:Function[]}= {};
    starts:{[key:string]:Function[]}= {};
    ends:{[key:string]:Function[]}= {};

    constructor(spine:sp.Skeleton,trackIndex:number = 0){
        super();
        this.spine = spine;
        this.trackIndex = trackIndex;
        
        spine.timeScale = 1.25;

        //设置监听
        this.spine.setEventListener(this.onEventListener.bind(this));
        //设置结束监听
        this.spine.setCompleteListener(this.onEndListener.bind(this));
        // //因为SpineBUG所以不使用Spine监听 采用自己调用
        // this.spine.setStartListener(this.onStartListener.bind(this));
    }

    open(){
        super.open();
        //重置
        Object.values(this.process).forEach(info => {
            info.track = null;
        })
    }

    //添加事件监听
    addEventListener(event:string,fun:Function){
        if(!this.events[event]) this.events[event] = [];
        this.events[event].push(fun);
    }

    //监听动画开始播放
    addStartListener(name:string,fun:Function){
        if(!this.starts[name]) this.starts[name] = [];
        this.starts[name].push(fun);
    }
    //监听动画结束播放
    addEndListener(name:string,fun:Function){
        if(!this.ends[name]) this.ends[name] = [];
        this.ends[name].push(fun);
    }

    //删除事件监听
    delEventListener(event:string,fun:Function){
        if(!this.events[event]) this.events[event] = [];
        let index = this.events[event].indexOf(fun);
        if(index >= 0) this.events[event].splice(index,1)
    }

    //删除动画开始播放
    delStartListener(name:string,fun:Function){
        if(!this.starts[name]) this.starts[name] = [];
        let index = this.starts[name].indexOf(fun);
        if(index >= 0) this.starts[name].splice(index,1)
    }
    //删除动画结束播放
    delEndListener(name:string,fun:Function){
        if(!this.ends[name]) this.ends[name] = [];
        let index = this.ends[name].indexOf(fun);
        if(index >= 0) this.ends[name].splice(index,1)
    }

    onEventListener(entry: sp.spine.TrackEntry, ev: sp.spine.Event){
        if(!this.events[ev.data.name]) this.events[ev.data.name] = [];
        this.events[ev.data.name].forEach(fun => {
            fun();
        });
    }

    onStartListener(entry: sp.spine.TrackEntry){
        if(!this.starts[entry.animation.name]) this.starts[entry.animation.name] = [];
        this.starts[entry.animation.name].forEach(fun => {
            fun();
        });
    }

    onEndListener(entry: sp.spine.TrackEntry){
        if(!this.ends[entry.animation.name]) this.ends[entry.animation.name] = [];
        this.ends[entry.animation.name].forEach(fun => {
            fun();
        });
    }

    // 流程图
    process: { [key: number]: GFSMProcessAnimInfo; } = {}

    execute(process:GFSMProcessAnimInfo,dt:number,frame:JNFrameInfo){
        process.ifTo = process.ifTo || [];
        process.to = process.to || [];
        process.mode = GFSMProcessMode.WaitExecute;
        process.execute = this.tick.bind(this);
        super.execute(process,dt,frame);
    }

    //-1 继续播放 0 重新执行流程 * 指定分支
    tick(dt:number,info:GFSMProcessAnimInfo,frame:JNFrameInfo){
        
        //判断是否会切换动画 (默认不切换)
        let to = GFSMProcessEnum.Wait;
        info.ifTo.forEach((run,index) => {
            if(run()){
                to = info.to[index];
            }
        });

        if(to >= 0) {
            //和下一个动作融合
            let mix = info.mixs[to - 1] || 0;
            if(mix){
                //设置融合
                this.spine.setMix(info.animName,this.process[to].animName,mix);
            }
            info.track = null;
            return to;
        }

        //播放动画
        if(!info.track){
            // console.log(`${frame.index} 播放动画-${this.spine.getComponent(GObject).nId}-`,info);
            info.track = this.spine.setAnimation(this.trackIndex,info.animName,!!info.isLoop);
            this.onStartListener(info.track);
        }

        return to;

    }

}

