import Container from "../display/Container";
import Texture from "../texture/Texture";
import Sprite from "../display/Sprite";
import { Event } from "../events/Event";

import { TextureCache, getCreateImage } from "../utils";
import { RAD_TO_DEG } from "../const";
import { Matrix } from "../math";

/**
 * 用于播放动画
 * 帧数监听，已ued给的文件为主，不做补间增加帧数，
 * 暂无setImage,setText再加
 * 暂时无矢量图和遮罩解析
 * 暂不支持加快播放，
 * 暂不支持loops循环次数
 * 考虑是否支持加快播放，如果能加速，中间帧数监听会出问题
 * 考虑是否帧率锁步，同上问题,锁步后会可能失效currentFrame判断
 * s.addEventListener(Event.ENTER_FRAME, func = (e) => {
 *      //这个判断如果只希望执行一次得多加一个条件isInTimeFrame为true，或者及时移除
 *      if (e.target.currentFrame == 66&&e.target.isInTimeFrame) {
 *         e.target.removeEventListener(Event.ENTER_FRAME, func);
 *    }
 * });
 * 锁步时的每帧监听，用>或<判断，及时移除
 * @class MovieClip
 * @since 1.0.0
 * @public
 * @extends Container
 */
export class MovieClip extends Container {

    /**
     * 锁步将按时间间隔来执行动画
     */
    public lockStep: boolean = false;
    /**
     * mc的当前帧,从1开始
     * @property currentFrame
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 1
     * @readonly
     */
    public get currentFrame(): number {
        return this._curFrame;
    }

    /**
     * @property _curFrame
     * @type {number}
     * @private
     * @since 2.0.0
     * @default 1
     */
    private _curFrame: number = 1;

    /**
     * 当前动画是否处于播放状态
     * @property isPlaying
     * @readOnly
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default true
     * @readonly
     */
    public get isPlaying(): boolean {
        return this._isPlaying;
    }

    /**
     * @property _isPlaying
     * @type {boolean}
     * @private
     * @since 2.0.0
     * @default true
     */
    private _isPlaying: boolean = true;

    /**
     * 动画的播放方向,是顺着播还是在倒着播
     * @property isFront
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default true
     * @readonly
     */
    get isFront(): boolean {
        return this._isFront;
    }

    /**
     * @property _isFront
     * @type {boolean}
     * @private
     * @default true
     */
    private _isFront: boolean = true;

    /**
     * 当前动画的总帧数
     * @property totalFrames
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 1
     * @readonly
     */
    public totalFrames: number;

    public videoWidth: number;
    public videoHeight: number;
    /**
     * 所有textures缓存
     */
    private textures = {};

    /**
     * 锁步的时间间隔，按fps定,毫秒
     */
    private timeInterval;

    /**
     * 前提引擎按60设置
     */
    private deltaFrame: number;
    /**
     * 中间帧计时
     */
    private frameCount: number = 0;
    /**
     * 构造函数
     * @method MovieClip
     * @public
     * @param mv VideoEntity格式，这里不给了
     */
    public constructor(mv?) {
        super();
        let s: any = this;
        s._instanceType = "MovieClip";
        //初始化
        if (mv) {
            s.init(mv);
        } else {
            s.totalFrames = 0;
        }
    }

    /**
     * 可以手动用init，
     * @param mv 
     */
    init(mv) {
        //记录基本信息，fps，每秒输出帧数，frames，总帧数，videoSize暂时不管
        //如果fps小于60怎么处理。update时怎么处理
        this.timeInterval = 1000 / mv.FPS;
        this.startTime = Date.now();
        this.startFrame = 1;
        this.totalFrames = mv.frames
        //间隔帧数，
        this.deltaFrame = 60 / mv.FPS;
        this.frameCount = this.deltaFrame;
        this._curFrame = 1;

        this.videoWidth = mv.videoSize.width;
        this.videoHeight = mv.videoSize.height;
        //考虑是否要加遮罩，用videoSize，暂时不用，为了性能
        // var mask = new Graphics();
        // mask.beginFill(0xffffff, 1);
        // mask.drawRect(0, 0, mv.videoSize.width, mv.videoSize.height);
        // mask.endFill();
        // this.mask = mask;

        //缓存所有图片
        const images = mv.images;
        if (mv.hasBeenCached) {
            //如已被缓存，则直接取了赋值
            for (var keyName in images) {

                this.textures[keyName] = TextureCache[keyName];
            }
            this.initChildren(mv.sprites)
        } else {
            //合图有bug，先不合了
            // if (GlobalPro.stageRenderType == RENDERER_TYPE.WEBGL) {
            //     //缓存成一张canvas，考虑要不要把所有资源搞成图集
            //     DrawAllToCanvas(images, (t) => {
            //         this.textures = t;
            //         this.initChildren(mv.sprites)
            //         //缓存
            //         for (var key in this.textures) {
            //             Texture.addToCache(this.textures[key], key)
            //         }
            //         mv.hasBeenCached = true;
            //     })
            // } else {
            //canvas直接缓存
            for (var key in images) {
                var bitmap = images[key];
                // let imgTag = document.createElement('img');

                let imgTag = getCreateImage()();
                let backCanvas;
                if (bitmap.indexOf("iVBO") === 0 || bitmap.indexOf("/9j/2w") === 0) {
                    imgTag.src = 'data:image/png;base64,' + bitmap;
                }
                else {
                    imgTag.src = bitmap;
                    //这里有问题，再说
                    // if (frames[0] && frames[0].layout) {
                    //     backCanvas = document.createElement('canvas');
                    //     backCanvas.width = frames[0].layout.width
                    //     backCanvas.height = frames[0].layout.height
                    //     imgTag.onload = function () {
                    //         backCanvas.getContext('2d').drawImage(imgTag, 0, 0, frames[0].layout.width, frames[0].layout.height)
                    //     }
                    // }
                }
                this.textures[key] = Texture.from(backCanvas || imgTag);
                // this.textures[key].once("loaded",()=>{
                //     是否监听加载完成？
                // })
                //考虑到key和已有缓存冲突，svga的都单独自己缓存，外部不可用，以后有时间搞
                Texture.addToCache(this.textures[key], key)
            }
            mv.hasBeenCached = true;
            this.initChildren(mv.sprites)
            // }
        }
    }

    private initChildren(sprites) {
        for (var i = 0, len = sprites.length; i < len; i++) {
            var ele = sprites[i];
            if (ele.imageKey) {
                var child = new Sprite(this.textures[ele.imageKey]);
                //直接赋值矩阵
                child["frames"] = ele.frames;
                child.transform.localMatrix.copy(ele.frames[0].transform);
                child.transform._parentID = -1;
                this.addChild(child);
                //透明度处理
                if (ele.frames[0].alpha < 0.05) {
                    child.visible = false;
                } else {
                    child.alpha = ele.frames[0].alpha;
                }
                //记录一个源数据
                child["framesOri"] = ele.frames;
                //记录一个源imageKey
                child["imageKey"] = ele.imageKey;
                //记录一个标识
                child["matteKey"] = ele.matteKey;
            }
        }
    }

    /**
     * 用基础属性重置
     * @param display 
     * @param transform 
     */
    private resetTransform(display, transform) {
        display.x = transform.tx;
        display.y = transform.ty;
        display.scaleX = transform.a;
        display.scaleY = transform.d;
        display.rotation = Math.round(Math.atan2(transform.b, transform.a) * RAD_TO_DEG);
    }

    /**
     * 用基础属性重置所有的待frame的children
     * @param frameIndex 帧 1到total
     */
    public resetTransformAll(frameIndex: number) {
        if (frameIndex > this.totalFrames) frameIndex = this.totalFrames;
        if (frameIndex <= 0) frameIndex = 1;
        for (var i = 0; i < this.children.length; i++) {
            let child = this.children[i];
            if (child["frames"] && child["frames"][frameIndex - 1]) {
                this.resetTransform(child, child["frames"][frameIndex - 1].transform)
            }
        }

    }

    /**
     * 
     * @param imagekey 对应的imagekey
     * @param imageUrl 图片路径，以后考虑支持多种形式
     */
    setImage(imagekey, imageUrl: string) {
        if (!this.textures[imagekey]) return
        let texture = this.textures[imagekey]
        var width = texture.width;
        var height = texture.height;
        let image = getCreateImage()();
        var self = this;
        image.onload = function () {
            let newTexture: Texture
            if (image.width == width && image.height == height) {
                newTexture = Texture.from(image);
            } else {
                var canvas = document.createElement("canvas");
                canvas.width = width;
                canvas.height = height;
                var ctx = canvas.getContext("2d")
                //适配绘制,为了全部显示在canvas中
                var scaleCan = width / height;
                var scale = image.width / image.height;
                if (scaleCan > scale) {
                    //定高
                    ctx.drawImage(image, 0, 0, image.width, image.height
                        , (width - scale * height) / 2, 0, scale * height, height)
                } else {
                    //定宽
                    ctx.drawImage(image, 0, 0, image.width, image.height
                        , 0, (height - width / scale) / 2, width, width / scale)
                }
                newTexture = Texture.fromCanvas(canvas)
            }
            //修改textures指向
            // self.textures[imagekey]=Texture.fromCanvas(canvas)
            //修改相应sprite
            for (var i = 0; i < self.children.length; i++) {
                let child = self.children[i]
                //texture相等
                if (child["imageKey"] == imagekey) {
                    child.texture = newTexture
                }
            }
        }
        image.src = imageUrl;
    }

    /**
     * 调用止方法将停止当前帧
     * @method stop
     * @public
     * @since 1.0.0
     */
    public stop(): void {
        let s = this;
        s._isPlaying = false;
    }

    /**
     * 将播放头向后移一帧并停在下一帧,如果本身在最后一帧则不做任何反应
     * @method nextFrame
     * @since 1.0.0
     * @public
     */
    public nextFrame(): void {
        let s = this;
        if (s._curFrame < s.totalFrames) {
            s._curFrame++;
        }
        s._isPlaying = false;
    }

    /**
     * 将播放头向前移一帧并停在下一帧,如果本身在第一帧则不做任何反应
     * @method prevFrame
     * @since 1.0.0
     * @public
     */
    public prevFrame(): void {
        let s = this;
        if (s._curFrame > 1) {
            s._curFrame--;
        }
        s._isPlaying = false;
    }

    /**
     * 将播放头跳转到指定帧并停在那一帧,如果本身在第一帧则不做任何反应
     * @method gotoAndStop
     * @public
     * @since 1.0.0
     * @param {number} frameIndex 批定帧的帧数或指定帧的标签名
     */
    public gotoAndStop(frameIndex: number): void {
        let s: any = this;
        s._isPlaying = false;
        if (frameIndex > s.totalFrames) {
            frameIndex = s.totalFrames;
        }
        if (frameIndex < 1) {
            frameIndex = 1;
        }
        s._curFrame = <number>frameIndex;
    }

    /**
     * 如果当前时间轴停在某一帧,调用此方法将继续播放.
     * @method play
     * @public
     * @since 1.0.0
     */
    public play(isFront: boolean = true): void {
        let s = this;
        s.frameCount = s.deltaFrame;
        s.startTime = Date.now();
        s.startFrame = s._curFrame;
        s._isPlaying = true;
        s._isFront = isFront;
    }

    /**
     * @property _lastFrame
     * @type {number}
     * @private
     * @default 0
     */
    private _lastFrame: number = 0;

    /**
     * 刚执行到的帧数，用于帧监听时判断用，刚好执行到当前帧，而不是之前保留的状态
     * 不是60fps的videoItem的中间有几帧curFrame会不变，判断只执行一次监听时会出错，刚好动画满帧60fps时就无所谓
     */
    public get isInTimeFrame(): boolean {
        //相等时就是刚开始的curFrame
        return this.frameCount == this.deltaFrame;
    }


    /**
     * 将播放头跳转到指定帧并从那一帧开始继续播放
     * @method gotoAndPlay
     * @public
     * @since 1.0.0
     * @param {number} frameIndex 批定帧的帧数或指定帧的标签名
     * @param {boolean} isFront 跳到指定帧后是向前播放, 还是向后播放.不设置些参数将默认向前播放
     */
    public gotoAndPlay(frameIndex: number, isFront: boolean = true): void {
        let s: any = this;
        s._isFront = isFront;
        s._isPlaying = true;
        if (frameIndex > s.totalFrames) {
            frameIndex = s.totalFrames;
        }
        if (frameIndex < 1) {
            frameIndex = 1;
        }
        s.frameCount = s.deltaFrame;
        s.startTime = Date.now();
        s._curFrame = <number>frameIndex;
        s.startFrame = s._curFrame;
    }

    /**
     * 记录的startAniRange对应的fun
     */
    private startAniRangeFun: Function
    /**
     * 优先级最高，会覆盖
     * @param beginFrame 默认1
     * @param endFrame 默认 this.totalFrames
     * @param loops 默认1 0
     */
    public startAniRange(
        beginFrame: number = 1,
        endFrame: number = this.totalFrames,
        loops: number = 1,
        callback?: Function
    ) {
        if (beginFrame < 1) {
            beginFrame = 1;
        }
        if (beginFrame > this.totalFrames) {
            beginFrame = this.totalFrames;
        }
        if (endFrame < 1) {
            endFrame = 1;
        }
        if (endFrame > this.totalFrames) {
            endFrame = this.totalFrames;
        }
        if (beginFrame === endFrame) {
            this.gotoAndStop(beginFrame)
            //如果相等
            return
        } else if (beginFrame < endFrame) {
            this._isFront = true;

        } else {
            this._isFront = false;
            var temp = beginFrame;
            beginFrame = endFrame;
            endFrame = temp;
        }
        //移除原先的绑定吧
        if (this.startAniRangeFun) this.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this)
        this._curFrame = beginFrame;
        //赋值count最大
        this.frameCount = this.deltaFrame;
        this.startTime = Date.now();
        this.startFrame = this._curFrame;
        this._isPlaying = true;

        let loopCount = loops ? (loops + 0.5 >> 0) : Infinity;
        this.addEventListener(Event.ENTER_FRAME, this.startAniRangeFun = (e) => {
            if (e.target._isFront) {
                //用大于等于可以避免锁步时出现的问题
                if (e.target.currentFrame >= endFrame || e.target._endMark) {
                    loopCount--;
                    if (loopCount <= 0) {
                        e.target.gotoAndStop(endFrame);
                        e.target.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
                        this.startAniRangeFun = null;
                        callback && callback();
                    } else {
                        e.target.gotoAndPlay(beginFrame);
                    }
                }
            } else {
                if (e.target.currentFrame <= beginFrame || e.target._endMark) {
                    loopCount--
                    if (loopCount <= 0) {
                        e.target.gotoAndStop(beginFrame);
                        e.target.removeEventListener(Event.ENTER_FRAME, this.startAniRangeFun, this);
                        this.startAniRangeFun = null;
                        callback && callback();
                    } else {
                        e.target.gotoAndPlay(endFrame, false);
                    }
                }
            }
        }, this)
    }

    /**
     * 开始时间，每次有play的时候就需要重置now
     * 锁步思想，设置开始时间，后面每帧实际时间与开始时间相减，得到当前帧数
     * 
     */
    private startTime: number;
    /**
     * 开始时的frame
     */
    private startFrame: number;

    /**
     * 与startFrame相间隔的帧数量，绝对值
     */
    private lastDeltaFrame: number
    /**
     * 锁步时的每次end的标识
     */
    private _endMark: boolean

    commonDeltaTime = 1000 / 60;
    updateFrame() {
        var s = this;
        //1帧的时候也有相应的frameCount，无用，return
        if (s.totalFrames == 0 || s.totalFrames == 1) return;
        let isNeedUpdate = false;
        if (s._lastFrame != s._curFrame) {
            //帧不相等
            isNeedUpdate = true;
            s._lastFrame = s._curFrame;

            //锁步的时候
            s.startTime = Date.now();
            s.startFrame = s._curFrame;

            s._endMark = false;
        } else {
            if (s._isPlaying) {
                if (s.lockStep) {
                    isNeedUpdate = s.getCurFrameWhenLockStep();
                } else {
                    if (--s.frameCount == 0) {
                        s.frameCount = s.deltaFrame;
                        isNeedUpdate = true;
                        if (s._isFront) {
                            s._curFrame++;
                            if (s._curFrame > s.totalFrames) {
                                s._curFrame = 1;
                            }
                        } else {
                            s._curFrame--;
                            if (s._curFrame < 1) {
                                s._curFrame = s.totalFrames;
                            }
                        }
                        s._lastFrame = s._curFrame;
                    }
                }
            }
        }
        //如果需要更新
        if (isNeedUpdate) {
            //对每个child还原对应的transform，alpha为0的默认visible设为false,避免计算
            for (var i = 0, len = s.children.length; i < len; i++) {
                var child = s.children[i]
                //只修改动画加入的child，不修改手动加入的，,所以想要修改动画中的元素属性，直接去掉frames属性，将不会执行动画
                if (child["frames"] && child["frames"][s._curFrame - 1]) {
                    var frame = child["frames"][s._curFrame - 1];
                    //layout不晓得干嘛用，暂不管
                    if (frame.alpha < 0.05) {
                        child.visible = false;
                    } else {
                        child.visible = true;
                        child.alpha = frame.alpha;
                        //先判断transform是否相等
                        if (!Matrix.isEqual(child.transform.localMatrix, frame.transform)) {
                            child.transform.localMatrix.copy(frame.transform)
                            child.transform._parentID = -1;
                        }
                    }
                }
            }
            //事件播放结束监听
            if (!s.lockStep) {
                if (((s._curFrame == 1 && !s._isFront) || (s._curFrame == s.totalFrames && s._isFront)) && s.hasEventListener(Event.END_FRAME)) {
                    s.dispatchEvent(Event.END_FRAME, {
                        frameIndex: s._curFrame,
                        frameName: "endFrame"
                    });
                }
            } else {
                //锁步的时候另外判断
                if (s._endMark && s.hasEventListener(Event.END_FRAME)) {
                    s.dispatchEvent(Event.END_FRAME, {
                        frameIndex: s._curFrame,
                        frameName: "endFrame"
                    });
                }
            }
        }

    }

    private getCurFrameWhenLockStep() {
        var dateNow = Date.now()
        //相差
        var deltaFrame = ((dateNow - this.startTime) / this.timeInterval) >> 0;
        //间隔帧数与上一帧一致，就不执行
        if (deltaFrame == this.lastDeltaFrame) {
            //设置不等
            this.frameCount = 0;
            return false
        }
        this._endMark = false;
        //相等，刚好执行切换
        this.frameCount = this.deltaFrame;
        this.lastDeltaFrame = deltaFrame
        if (this._isFront) {
            //取余数
            this._curFrame = (this.startFrame + deltaFrame) % this.totalFrames;
            if (this._curFrame == 0) {
                this._curFrame = this.totalFrames;
                this._endMark = true;
            }
            //当上一帧大于_curFrame,并且上一帧不是totalFrames时，说明跳过了最后一帧
            else if (this._lastFrame > this._curFrame &&
                this._lastFrame != this.totalFrames) {
                this._endMark = true;
            }
        } else {
            this._curFrame = (this.startFrame - deltaFrame) % this.totalFrames;
            if (this._curFrame == 0) {
                this._curFrame = this.totalFrames;
            } else if (this._curFrame < 0) {
                this._curFrame += this.totalFrames;
            }
            if (this._curFrame == 1) {
                this._endMark = true;
            }
            //当上一帧小于_curFrame,并且上一帧不是1时，说明跳过了第一帧
            else if (this._lastFrame < this._curFrame &&
                this._lastFrame != 1) {
                this._endMark = true;
            }
        }
        this._lastFrame = this._curFrame;
        return true
    }
    /**
     * 重写刷新
     * @method update
     * @public
     * @since 1.0.0
     */
    public update(): void {
        let s: any = this;
        //更新帧数据
        this.updateFrame();
        super.update();
    }



    public destroy(): void {
        //todo-清除相应的数据引用

        super.destroy();
    }
}
