import { EventDispatcher, Event } from "./events";
import { clamp } from "./utils";

/**
 * 就是个时间轴，setValue和resetValue方法自行实现
 */
export interface IAnimationTrack {
    setValue: (time: number) => void
    resetValue: () => void
}
/**
 * 不需要挂到节点上
 * 暂时没有帧，只有时间，以后再说
 * 用update更新
 * 通用的动画类，track自定义
 */
export class AnimationClip extends EventDispatcher {
    name: string
    /**
     * 所有的动画数据
     */
    protected tracks: IAnimationTrack[];
    private _totalTime: number;
    /**
     * 动画总时长，一般是所有tracks里时间最长的那个
     * @readonly
     */
    get totalTime() {
        return this._totalTime;
    }
    /**
     * 
     * @param tracks 
     * @param totalTime 总时间自行传入，秒计，
     */
    constructor(tracks: IAnimationTrack[], totalTime: number) {
        super()
        this._instanceType = "AnimationClip"
        this.tracks = tracks;
        this._totalTime = totalTime
    }
    /**
     * 初始化方法
     * @param tracks 
     * @param totalTime 
     */
    init(tracks: IAnimationTrack[], totalTime: number) {
        this.tracks = tracks;
        this._totalTime = totalTime;
        //事件移除，其实帧数完全一致的话，不会出问题，一样能触发回调
        if (this.startAniRangeFun) this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);

        //下面这些暂时不考虑初始化，MovieClip暂时也没有，估计静止的时候都会出问题
        // this._isPlaying = true;
        // this._isFront = true;
        // this.lastTime = null;
        // this.curTime = 0;
        // this._endMark = false;
    }

    private _isPlaying: boolean = true;
    /**
     * 是否播放中
     * @readonly
     */
    public get isPlaying(): boolean {
        return this._isPlaying;
    }

    private _isFront: boolean = true;
    /**
     * 是否正向播放
     * @readonly
     */
    get isFront(): boolean {
        return this._isFront;
    }

    /**
     * 上个时间，用来确定是否更新
     */
    protected lastTime: number = null;
    /**
     * 记录时间
     */
    protected curTime: number = 0;
    /**
     * 当前时间
     */
    get currentTime() {
        return this.curTime;
    }

    private _endMark: boolean = false;
    /**
     * 需要挂在循环里的方法，传时间间隔
     * @param time 一般为秒计
     */
    update(time: number) {
        if (!this.tracks || !this.tracks.length) return;
        //时间不等，直接播放
        if (this.curTime !== this.lastTime) {
            this.rectify();
            this._endMark = false;
            return;
        }
        //时间没有，或没在播放
        if (time <= 0 || !this._isPlaying) return;
        this._endMark = false;
        if (this._isFront) {
            this.curTime += time;
            if (this.curTime > this._totalTime) {
                this.curTime = 0;
                this._endMark = true;
            }
        } else {
            this.curTime -= time;
            if (this.curTime < 0) {
                this.curTime = this._totalTime;
                this._endMark = true;
            }
        }
        if (this.curTime !== this.lastTime) {
            //矫正
            this.rectify();
            //派发每帧事件
            this.dispatchEvent(Event.ENTER_FRAME);
            //派发结束帧事件
            if (this._endMark && this.hasEventListener(Event.END_FRAME)) {
                this.dispatchEvent(Event.END_FRAME);
            }
        }
    }
    /**
     * 从当前时间点播放
     * @param isFront 默认true正向
     */
    play(isFront: boolean = true) {
        this._isFront = isFront;
        this._isPlaying = true;
    }
    /**
     * 停在当前时间
     */
    stop() {
        this._isPlaying = false;
        this.lastTime = this.curTime;
    }
    /**
     * 从某时刻开始播放
     * @param time 
     * @param isFront 默认true，正向播放
     */
    public gotoAndPlay(time: number, isFront: boolean = true): void {
        let s = this;
        s._isFront = isFront;
        s._isPlaying = true;
        // if (time > s._totalTime) time = s._totalTime;
        // if (time < 0) time = 0;
        time = clamp(time, 0, s._totalTime);//改成用clamp
        s.curTime = time;
    }
    /**
     * 停在指定时间
     * @param time 
     * @param force 是否强制更新，默认false，如果发现没stop在指定位置，可以试试设置true
     */
    public gotoAndStop(time: number, force: boolean = false): void {
        this._isPlaying = false;
        // if (time > this.totalTime) time = this.totalTime;
        // if (time < 0) time = 0;
        time = clamp(time, 0, this._totalTime);//改成用clamp
        this.curTime = time;
        //这样会强制更新
        if (force) this.lastTime = null
    }

    private startAniRangeFun;

    /**
     * 在一个区间范围内播放
     * @param beginTime 开始时间，秒计，默认0，
     * @param endTime 结束时间，秒计，默认_totalTime
     * @param loops 循环次数，默认1，0表示无限循环
     * @param callback 参数loop表示还剩几次
     */
    public startAniRange(
        beginTime: number = 0,
        endTime: number = this._totalTime,
        loops: number = 1,
        callback?: (loop: number) => void
    ) {
        //loops处理下
        loops = loops || 0;//去掉null等等
        loops = Math.max(0, loops);//去掉负数

        // if (beginTime <= 0) beginTime = 0;
        // if (beginTime > this._totalTime) beginTime = this._totalTime;
        // if (endTime <= 0) endTime = 0;
        // if (endTime > this._totalTime) endTime = this._totalTime;
        beginTime = clamp(beginTime, 0, this._totalTime);
        endTime = clamp(endTime, 0, this._totalTime);
        if (beginTime === endTime) {
            this.gotoAndStop(beginTime)
            //如果相等
            return
        } else if (beginTime < endTime) {
            this._isFront = true;
        } else {
            this._isFront = false;
            var temp = beginTime;
            beginTime = endTime;
            endTime = temp;
        }
        //移除原先的绑定吧
        if (this.startAniRangeFun) this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this)
        this.curTime = beginTime;
        this._isPlaying = true;
        let loopCount = loops ? (loops + 0.5 >> 0) : Infinity;
        this.addEventListener(Event.ENTER_FRAME, this.startAniRangeFun = (e: Event) => {
            let s: AnimationClip = e.target;
            if (s._isFront) {
                if (s.curTime >= endTime || s._endMark) {//
                    loopCount--;
                    if (loopCount <= 0) {
                        s.gotoAndStop(endTime);//这个在下一帧才生效，所以加一个矫正rectify
                        // s.rectify();
                        s.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
                        this.startAniRangeFun = null;
                        callback && callback(loopCount);
                        s.rectify();//放在最后吧，callback里也可能干了啥
                    } else {
                        s.gotoAndPlay(beginTime);
                    }
                }
            } else {
                if (s.curTime <= beginTime || s._endMark) {
                    loopCount--
                    if (loopCount <= 0) {
                        s.gotoAndStop(beginTime);//这个在下一帧才生效，所以加一个矫正rectify
                        // s.rectify();
                        s.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
                        this.startAniRangeFun = null;
                        callback && callback(loopCount);
                        s.rectify();//放在最后吧，callback里也可能干了啥
                    } else {
                        s.gotoAndPlay(endTime, false);
                    }
                }
            }
        }, this)
    }
    /**
     * 矫正
     */
    protected rectify() {
        if (!this.tracks || !this.tracks.length) return;
        for (var i = 0; i < this.tracks.length; i++) {
            this.tracks[i].setValue(this.curTime)
        }
        //设置相等
        this.lastTime = this.curTime;
    }

    /**
     * 用于重置初始状态，因为每个track的0状态也不一定是初始状态
     * 所以各自track自行处理
     */
    public resetState() {
        this.stop();
        for (var i = 0; i < this.tracks.length; i++) this.tracks[i].resetValue()
    }
}