import Container from "../display/Container";
import { VideoEntity } from "./VideoEntity";
import Texture from "../texture/Texture";
import Sprite from "../display/Sprite";
import { Event } from "../events/Event";
import Graphics from "../graphics/Graphics";
import { GlobalPro, TextureCache } from "../utils";
import { RENDERER_TYPE, RAD_TO_DEG } from "../const";
import { DrawAllToCanvas } from "../utils/DrawAllToCanvas";
import { Button } from "../ui/Button";
import { TextField } from "../text/TextField";
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;

    loops: number = 0;
    /**
     * 所有textures缓存
     */
    private textures = {};

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

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

    /**
     * 可以手动用init，
     * @param mv 
     */
    init(mv: VideoEntity) {
        if (mv.instanceType == "VideoEntity") {
            //记录基本信息，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;

            //考虑是否要加遮罩，用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 = new Image();
                    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
                var splitArr = ele.imageKey.split("_");
                //start_btn
                if (splitArr[1] && splitArr[1] == "btn") {
                    //如果是按钮,
                    child = new Button(this.textures[ele.imageKey]);
                    //去掉frames，保留单帧数据，
                    this.resetTransform(child, ele.frames[0].transform)
                    //存下指向start，
                    this[splitArr[0]] = child;
                }
                //需标记的带动画的，有动画矩阵，不能通过基础属性修改，最好已适配，否则单独导出，不放布局
                else if (splitArr[1] && splitArr[1] == "spr") {
                    child = new Sprite(this.textures[ele.imageKey]);
                    //直接赋值矩阵，实际有位置操作时，直接去掉frames属性，就不会被更新，如要还原，需临时记录
                    if (ele.frames.length > 1) {
                        child["frames"] = ele.frames;
                        child.transform.localMatrix.copy(ele.frames[0].transform);
                        child.transform._parentID = -1;
                    } else {
                        this.resetTransform(child, ele.frames[0].transform)
                    }
                    this[splitArr[0]] = child;
                }
                //文本
                else if (splitArr[1] && splitArr[1] == "text") {
                    //内容没法改，暂时用XXX代替，因为
                    child = new TextField();
                    child.text = "xxxx";
                    child.size = splitArr[2] ? parseInt(splitArr[2]) : 20;//字号
                    child.fillColor = splitArr[3] ? "#" + splitArr[3] : "#000000"//颜色
                    child.textAlign = splitArr[4] || "center"//水平对齐方式
                    child.textWidth = this.textures[ele.imageKey].width //假设已经加载
                    // child.border = true;
                    //直接赋值矩阵
                    child["frames"] = ele.frames;
                    child.transform.localMatrix.copy(ele.frames[0].transform);
                    child.transform._parentID = -1;
                    this[splitArr[0]] = child;
                    //如果有动画，不能通过基础属性修改位置，文案最好已适配
                }
                //一般不需要标记的
                else {
                    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;
            }
        }
    }

    /**
     * 用基础属性重置
     * @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 = new Image();
        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;
    }

    /**
     * 优先级最高，会覆盖
     * @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;
        }
        this._curFrame = beginFrame;
        //赋值count最大
        this.frameCount = this.deltaFrame;
        this.startTime = Date.now();
        this.startFrame = this._curFrame;
        this._isPlaying = true;
        let func;
        let loopCount = loops ? (loops + 0.5 >> 0) : Infinity;
        this.addEventListener(Event.ENTER_FRAME, func = (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, func);
                        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, func);
                        callback && callback();
                    } else {
                        e.target.gotoAndPlay(endFrame, false);
                    }
                }
            }
        })

    }

    /**
     * 开始时间，每次有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();
    }
}
