import Container from "./Container";
import { osType, devicePixelRatio, RENDERER_TYPE, StageScaleMode } from "../const"
import SystemRenderer from "../renderers/SystemRenderer";
import { Rectangle, Point } from "../math";
import { EventDispatcher } from "../events/EventDispatcher";
import { Event } from "../events/Event";
import { FloatDisplay } from "./FloatDisplay";
import { DisplayObject } from "./DisplayObject";
import { MouseEvent } from "../events/MouseEvent";

import { WebglRenderer } from "../renderers/WebglRenderer";
import { GDispatcher } from "../events/GDispatcher";
import CanvasRenderer from "../renderers/CanvasRenderer";
import { isWebGLSupported, GlobalPro } from "../utils";

//如果以后还出现帧率问题，使用ticker；
//兼容requestAnimationFrame
const requestAnimationFrame = (function () {
    var lastTime = 0;
    var vendors = ['webkit', 'moz'];
    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||    // name has changed in Webkit
            window[vendors[x] + 'CancelRequestAnimationFrame'];
    }
    let requestAnimationFrame: any = window.requestAnimationFrame;
    if (!requestAnimationFrame) {
        requestAnimationFrame = function (callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
            var id = window.setTimeout(function () {
                callback(currTime + timeToCall);
            }, timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
    }
    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function (id) {
            clearTimeout(id);
        };
    }
    return requestAnimationFrame
}())

export class Stage extends Container {

    /**
     * 是否阻止ios端双击后页面会往上弹的效果，因为如果阻止了，可能有些html元素出现全选框后无法取消
     * 所以需要自己灵活设置,默认阻止.
     * @property iosTouchendPreventDefault
     * @type {boolean}
     * @default true
     * @since 1.0.4
     * @public
     */
    public iosTouchendPreventDefault: boolean = true;
    /**
     * 是否禁止引擎所在的canvas的鼠标事件或触摸事件的默认形为，默认为true是禁止的。
     * @property isPreventDefaultEvent
     * @since 1.0.9
     * @default true
     * @type {boolean}
     */
    public isPreventDefaultEvent: boolean = true;
    /**
     * 整个引擎的最上层的div元素,
     * 承载canvas的那个div html元素
     * @property rootDiv
     * @public
     * @since 1.0.0
     * @type {Html Div}
     * @default null
     */
    public rootDiv: any = null;
    /**
     * 如果没有rootDiv就用下面这个;
     */
    public canvas: HTMLCanvasElement
    /**
     * 当前stage所使用的渲染器
     * 渲染器有两种,一种是canvas 一种是webGl
     * @property renderObj
     * @public
     * @since 1.0.0
     * @type {IRender}
     * @default null
     */
    public renderObj: SystemRenderer = null;
    /**
     * 渲染模式值 只读 CANVAS:2, webGl: 1
     * @property renderType
     * @readonly
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 0
     * @readonly
     */
    public renderType: number = 0;

    /**
     * 直接获取stage的引用，避免总是从Event.ADD_TO_STAGE 事件中去获取stage引用
     * @property getStage
     * @param {string} stageName
     * @return {any}
     * @since 2.0.0
     */
    public static getStage(stageName: string = "cusEngine"): Stage {
        return Stage._stageList[stageName];
    }

    /**
     * @property _stageList
     * @static
     * @type {Object}
     * @private
     */
    private static _stageList: any = {};
    /**
     * 是否暂停
     * @property pause
     * @static
     * @type {boolean}
     * @public
     * @since 1.0.0
     * @default false
     */
    static get pause(): boolean {
        return this._pause;
    }
    static set pause(value: boolean) {
        this._pause = value;
        if (value != this._pause) {
            //触发事件
            GDispatcher.dispatchEvent("onStagePause", { pause: value });
        }
    }

    /**
     * @property _pause
     * @type {boolean}
     * @private
     * @static
     */
    private static _pause: boolean = false;
    /**
     * 舞台在设备里截取后的可见区域,有些时候知道可见区域是非常重要的,因为这样你就可以根据舞台的可见区域做自适应了。
     * @property viewRect
     * @public
     * @readonly
     * @since 1.0.0
     * @type {Rectangle}
     * @default {x:0,y:0,width:0,height:0}
     * @readonly
     */
    public viewRect: Rectangle = new Rectangle();

    /**
     * 当设备尺寸更新，或者旋转后是否自动更新舞台方向
     * 端默认不开启
     * @property autoSteering
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default false
     */
    public autoSteering: boolean = false;
    /**
     * 当设备尺寸更新，或者旋转后是否自动更新舞台尺寸，
     * 这里修改还要考虑添加各层级适配的修改和滤镜帧缓存的修改，未实现，先不用
     * @property autoResize
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default false
     */
    public autoResize: boolean = false;
    /**
     * 舞台的尺寸宽,也就是我们常说的设计尺寸
     * @property desWidth
     * @public
     * @since 1.0.0
     * @default 320
     * @type {number}
     * @readonly
     */
    public desWidth: number = 0;
    /**
     * 舞台的尺寸高,也就是我们常说的设计尺寸
     * @property desHeight
     * @public
     * @since 1.0.0
     * @default 240
     * @type {number}
     * @readonly
     */
    public desHeight: number = 0;
    /**
     * 舞台在当前设备中的真实高
     * @property divHeight
     * @public
     * @since 1.0.0
     * @default 320
     * @type {number}
     * @readonly
     */
    public divHeight: number = 0;
    /**
     * 舞台在当前设备中的真实宽
     * @property divWidth
     * @public
     * @since 1.0.0
     * @default 240
     * @readonly
     * @type {number}
     */
    public divWidth: number = 0;
    /**
     * 舞台的背景色
     * 默认就是透明背景
     * 可能设置一个颜色值改变舞台背景
     * @property bgColor
     * @public
     * @since 1.0.0
     * @type {number}
     * @default "";
     */
    private _bgColor: number = 0x000000;

    public get bgColor(): number {
        return this._bgColor;
    }
    /**
     * 设置颜色，即改变渲染器颜色
     */
    public set bgColor(value: number) {
        if (this._bgColor === value) return
        this._bgColor = value;
        this.renderObj.backgroundColor = value;
    }

    /**
     * 舞台的缩放模式
     * 默认为空就是无缩放的真实大小
     * "noBorder" 无边框模式
     * ”showAll" 显示所有内容
     * “fixedWidth" 固定宽
     * ”fixedHeight" 固定高
     * @property scaleMode
     * @public
     * @since 1.0.0
     * @default "onScale"
     * @type {string}
     * @example
     *      //动态更改stage的对齐方式示例
     *      //以下代码放到一个舞台的显示对象的构造函数中
     *      let s=this;
     *      s.addEventListener(Event.ADD_TO_STAGE,function(e){
     *          let i=0;
     *          s.stage.addEventListener(MouseEvent.CLICK,function(e){
     *              let aList=[StageScaleMode.EXACT_FIT,StageScaleMode.NO_BORDER,StageScaleMode.NO_SCALE,StageScaleMode.SHOW_ALL,StageScaleMode.FIXED_WIDTH,StageScaleMode.FIXED_HEIGHT]
     *              let state=e.currentTarget;
     *              state.scaleMode=aList[i];
     *              state.resize();
     *              if(i>5){i=0;}
     *          }
     *      }
     *
     */
    get scaleMode(): string {
        return this._scaleMode;
    }

    set scaleMode(value: string) {
        let s = this;
        if (value != s._scaleMode) {
            s._scaleMode = value;
            s.setAlign();
        }
    }
    private _scaleMode: string = "onScale";

    /**
     * 原始为60的刷新速度时的计数器
     * @property _flush
     * @private
     * @since 1.0.0
     * @default 0
     * @type {number}
     */
    private _flush: number = 0;
    /**
     * 当前的刷新次数计数器
     * @property _currentFlush
     * @private
     * @since 1.0.0
     * @default 0
     * @type {number}
     */
    private _currentFlush: number = 0;
    /**
     * @property _dragDisplay
     * @private
     * @type {null}
     * @private
     * @static
     */
    public static _dragDisplay: DisplayObject = null;
    /**
     * 上一次鼠标或触碰经过的显示对象列表
     * @property _lastDpList
     * @type {Object}
     * @private
     */
    private _lastDpList: any = {};
    /**
     * 窗口resize计时器id
     * @property _rid
     * @type {number}
     * @private
     */
    private _rid: any = -1;
    /**
     * dom层记录
     * @property _floatDisplayList
     * @type {any[]}
     * @private
     */
    private _floatDisplayList: Array<FloatDisplay> = [];

    /**
     * 显示对象入口函数
     * @method Stage
     * @param {string} rootDivId 兼容，可传入canvas
     * @param {number} desW 舞台宽
     * @param {number} desH 舞台高
     * @param {number} frameRate 刷新率
     * @param {string} scaleMode 缩放模式 StageScaleMode
     * @param {number} renderType 渲染类型2canvas
     * @param {boolean} transparent 透明否，默认透明true,此时bgColor无效
     * @param {number} bgColor 背景颜色十六进制
     * @public
     * @since 1.0.0
     */
    public constructor(
        rootDivId: string | HTMLCanvasElement = "cusEngine",
        desW: number = 750,
        desH: number = 1206,
        frameRate: number = 60,
        scaleMode: string = StageScaleMode.FIXED_WIDTH,
        renderType: number = RENDERER_TYPE.WEBGL,
        transparent: boolean = true,
        bgColor: number = 0x000000
    ) {
        super();
        let s: Stage = this;
        this._instanceType = "Stage";
        s.stage = this;
        s.name = "stageInstance_" + s.instanceId;
        if (typeof rootDivId == "string") {
            Stage._stageList[rootDivId] = s;
            let div: any = document.getElementById(rootDivId);
            s.rootDiv = div;
            s.canvas = document.createElement("canvas");
            s.rootDiv.appendChild(s.canvas);
            s.canvas.id = "cusCanvas";
        } else {
            s.canvas = rootDivId;
        }

        s.renderType = renderType;
        s.desWidth = desW;
        s.desHeight = desH;
        s.setFrameRate(frameRate);
        s._scaleMode = scaleMode;
        s.anchorX = desW >> 1;
        s.anchorY = desH >> 1;


        if (renderType == RENDERER_TYPE.CANVAS) {
            //canvas
            s.renderObj = new CanvasRenderer({
                htmlElement: s.canvas,
                transparent: transparent,
                backgroundColor: bgColor
            });
            //记录全局属性
            GlobalPro.stageRenderType = RENDERER_TYPE.CANVAS
            console.log("渲染方式：canvas")
        } else {
            //webgl,先检测是否支持webgl
            if (isWebGLSupported()) {
                s.renderObj = new WebglRenderer({
                    htmlElement: s.canvas,
                    transparent: transparent,
                    // antialias:true,
                    preserveDrawingBuffer: false,
                    backgroundColor: bgColor
                });
                GlobalPro.stageRenderType = RENDERER_TYPE.WEBGL;
                console.log("webgl")
            } else {
                s.renderObj = new CanvasRenderer({
                    htmlElement: s.canvas,
                    transparent: transparent,
                    backgroundColor: bgColor
                });
                GlobalPro.stageRenderType = RENDERER_TYPE.CANVAS;
                console.log("渲染方式：canvas")
            }
        }

        let resizeEvent = "resize";
        window.addEventListener(resizeEvent, function (e: any) {
            clearTimeout(s._rid);
            s._rid = setTimeout(function () {
                if (s.autoResize) {
                    s.resize();
                }
                let event = new Event(Event.RESIZE);
                s.dispatchEvent(event);
            }, 300);
        });
        setTimeout(function () {
            s.resize();
            //同时添加到主更新循环中
            Stage.addUpdateObj(s);
            s.dispatchEvent(Event.INIT_STAGE);
            // }
        }, 100);
        let rc = s.rootDiv || s.canvas;//没有传div时直接用canvas，用canvas时，floatDisplay会遮挡
        let mouseEvent = s.onMouseEvent.bind(s);
        //鼠标事件
        if (osType != "pc") {
            rc.addEventListener("touchstart", mouseEvent, false);
            rc.addEventListener('touchmove', mouseEvent, false);
            rc.addEventListener('touchend', mouseEvent, false);
        } else {
            rc.addEventListener("mousedown", mouseEvent, false);
            rc.addEventListener('mousemove', mouseEvent, false);
            rc.addEventListener('mouseup', mouseEvent, false);
        }
    }

    /**
     * 主渲染函数
     * @method render
     */
    public render(): void {
        //放入渲染器中渲染
        this.renderObj.render(this);
        //dom层的更新
        let sf: any = this._floatDisplayList;
        let len = sf.length;
        for (let i = 0; i < len; i++) {
            sf[i].updateStyle();
        }
    }

    /**
     * 这个是鼠标事件的MouseEvent对象池,因为如果用户有监听鼠标事件,如果不建立对象池,那每一秒将会new Fps个数的事件对象,影响性能
     * @property _ml
     * @type {Array}
     * @private
     */
    private _ml: any = [];
    /**
     * 这个是事件中用到的Point对象池,以提高性能
     * @property _mp
     * @type {Array}
     * @private
     */
    private _mp: any = [];

    /**
     * 刷新mouse或者touch事件
     * @method _initMouseEvent
     * @private
     */
    private _initMouseEvent(event: MouseEvent, cp: Point, sp: Point, identifier: number): void {
        event["_pd"] = false;
        event.clientX = cp.x;
        event.clientY = cp.y;
        event.stageX = sp.x;
        event.stageY = sp.y;
        event.identifier = identifier;
    }

    //每一个手指事件的对象池
    /**
     * @property _mouseDownPoint
     * @type {Object}
     * @private
     */
    private _mouseDownPoint: any = {};

    /**
     * 循环刷新页面的函数
     * @method flush
     * @private
     * @return {void}
     */
    public flush(): void {
        let s = this;
        if (s._flush == 0) {
            s.render();
        } else {
            if (s._currentFlush == 0) {
                s.render();
                s._currentFlush = s._flush;
            } else {
                s._currentFlush--;
            }
        }
    }

    /**
     * 引擎的刷新率,就是一秒中执行多少次刷新
     * @method setFrameRate
     * @param {number} fps 最好是60的倍数如 1 2 3 6 10 12 15 20 30 60
     * @since 1.0.0
     * @public
     */
    public setFrameRate(fps: number): void {
        let s = this;
        s._flush = 60 / fps - 1 >> 0;
        if (s._flush < 0) {
            s._flush = 0;
        }
    }

    /**
     * 引擎的刷新率,就是一秒中执行多少次刷新
     * @method getFrameRate
     * @since 1.0.0
     * @public
     */
    public getFrameRate(): number {
        return 60 / (this._flush + 1);
    }

    /**
     * 获取引擎所在的div宽高
     * @method getRootDivWH
     * @public
     * @since 1.0.0
     * @param {HTMLDivElement} div
     * @return {{w: number, h: number}}
     */
    public getRootDivWH(div: HTMLDivElement) {
        let sw = div.style.width;
        let sh = div.style.height;
        let iw = document.body.clientWidth;
        let ih = document.body.clientHeight;
        let vW = parseInt(sw);
        let vH = parseInt(sh);
        if (vW.toString() == "NaN") {
            vW = iw;
        } else {
            if (sw.indexOf("%") > 0) {
                vW *= iw / 100;
            }
        }
        if (vH.toString() == "NaN") {
            vH = ih;
        } else {
            if (sh.indexOf("%") > 0) {
                vH *= ih / 100;
            }
        }
        return { w: vW, h: vH };
    }

    /**
     * 当一个stage不再需要使用,或者要从浏览器移除之前,请先停止它,避免内存泄漏
     * @method kill
     * @since 1.0.0
     * @public
     */
    public kill(): void {
        Stage.removeUpdateObj(this);
    }

    /**
     * html的鼠标或单点触摸对应的引擎事件类型名
     * @property _mouseEventTypes
     * @type {{mousedown: string, mouseup: string, mousemove: string, touchstart: string, touchmove: string, touchend: string}}
     * @private
     */
    private _mouseEventTypes: any = {
        mousedown: "onMouseDown",
        mouseup: "onMouseUp",
        mousemove: "onMouseMove",
        touchstart: "onMouseDown",
        touchmove: "onMouseMove",
        touchend: "onMouseUp"
    };

    /**
     * 无多指，无拖动
     * @method onMouseEvent
     * @param e
     * @private
     */
    private onMouseEvent(e: any): void {
        let s: Stage = this;
        //检查mouse或touch事件是否有，如果有的话，就触发事件函数
        if (EventDispatcher._totalMEC > 0) {
            let points: any;
            //事件类型
            let item = s._mouseEventTypes[e.type];
            let events: any;
            let event: any;
            //stageMousePoint
            let sp: Point;
            //localPoint;
            let lp: Point;
            //clientPoint
            let cp: Point;
            //事件个数
            let eLen: number;
            let identifier: any;
            if (osType == "pc") {
                e.identifier = 0;
                points = [e];
            } else {
                points = [e.changedTouches[0]];
            }
            for (let o = 0; o < points.length; o++) {
                eLen = 0;
                events = [];
                identifier = "m" + points[o].identifier;
                if (s._mp.length > 0) {
                    cp = s._mp.shift();
                } else {
                    cp = new Point();
                }
                //计算偏移,如有偏移试下改pageXOffset
                let doc = document.documentElement;
                //用points[o].target可能监听到FloatDisplay，用s.rootDiv不晓得有其他FloatDisplay存在时会不会撑开
                let box = s.canvas.getBoundingClientRect();
                let left = box.left + window.pageXOffset - doc.clientLeft;
                let top = box.top + window.pageYOffset - doc.clientTop;
                cp.x = (points[o].pageX || points[o].x || points[o].b - left) * devicePixelRatio;//讲道理不会这么准是0，所以不管
                cp.y = (points[o].pageY || points[o].y || points[o].c - top) * devicePixelRatio;
                //如有偏移问题再改
                // cp.x = (points[o].clientX - points[o].target.offsetLeft + window.pageXOffset) * devicePixelRatio;
                // cp.y = (points[o].clientY - points[o].target.offsetTop + window.pageYOffset) * devicePixelRatio;
                //计算舞台中的点
                sp = s.globalToLocal(cp, DisplayObject._bp);
                //检查是否有鼠标事件
                if (EventDispatcher.getMouseEventCount() > 0) {
                    if (!s._ml[eLen]) {
                        event = new MouseEvent(item);
                        s._ml[eLen] = event;
                    } else {
                        event = s._ml[eLen];
                        event.type = item;
                    }
                    events[events.length] = event;
                    s._initMouseEvent(event, cp, sp, identifier);
                    eLen++;
                }
                if (item == "onMouseDown") {
                    s._mouseDownPoint[identifier] = cp;
                    //清空上次存在的显示列表
                } else if (item == "onMouseUp") {
                    if (s._mouseDownPoint[identifier]) {
                        if (Point.distance(s._mouseDownPoint[identifier], cp) < 20) {
                            //检查是否有添加对应的click事件
                            if (EventDispatcher.getMouseEventCount("onMouseClick") > 0) {
                                if (!s._ml[eLen]) {
                                    event = new MouseEvent("onMouseClick");
                                    s._ml[eLen] = event;
                                } else {
                                    event = s._ml[eLen];
                                    event.type = "onMouseClick";
                                }
                                events[events.length] = event;
                                s._initMouseEvent(event, cp, sp, identifier);
                                eLen++;
                            }
                        }
                    }
                }
                if (eLen > 0) {
                    //有事件开始遍历显示列表
                    //找出最底层的显示对象
                    let d: DisplayObject = s.hitTestPoint(cp, true);
                    // console.log(d)
                    let displayList: Array<DisplayObject> = [];
                    if (d) {
                        //证明有点击到事件,然后从最底层追上来,看看一路是否有人添加过mouse或touch事件,还要考虑mousechildren和阻止事件方法
                        //找出真正的target,因为有些父级可能会mouseChildren=false;
                        while (d) {
                            if (d["mouseChildren"] === false) {
                                //丢掉之前的层级,因为根本没用了
                                displayList.length = 0;
                            }
                            displayList[displayList.length] = d;
                            d = d.parent;
                        }
                    } else {
                        displayList[displayList.length] = s;
                    }
                    let len: number = displayList.length;
                    for (let i = len - 1; i >= 0; i--) {
                        d = displayList[i];
                        for (let j = 0; j < eLen; j++) {
                            if (!events[j]["_pd"]) {
                                //有事件，且mouseEnable为true
                                if (d.hasEventListener(events[j].type) && d.mouseEnable) {
                                    events[j].target = d;
                                    events[j].currentTarget = displayList[0];
                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                    events[j].localX = lp.x;
                                    events[j].localY = lp.y;
                                    d.dispatchEvent(events[j]);
                                }
                            }
                        }
                    }
                    //这里一定要反转一下，因为会影响mouseOut mouseOver
                    displayList.reverse();
                    for (let i = len - 1; i >= 0; i--) {
                        d = displayList[i];
                        for (let j = 0; j < eLen; j++) {
                            if (!events[j]["_pd"]) {
                                //有事件，且mouseEnable为true
                                if (d.hasEventListener(events[j].type, false) && d.mouseEnable) {
                                    events[j].target = d;
                                    events[j].currentTarget = displayList[eLen - 1];
                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                    events[j].localX = lp.x;
                                    events[j].localY = lp.y;
                                    d.dispatchEvent(events[j], null, false);
                                }
                            }
                        }
                    }
                    //最后要和上一次的遍历者对比下，如果不相同则要触发onMouseOver和onMouseOut
                    if (item != "onMouseDown") {
                        if (EventDispatcher.getMouseEventCount("onMouseOver") > 0 || EventDispatcher.getMouseEventCount("onMouseOut") > 0) {
                            if (s._lastDpList[identifier]) {
                                //从第二个开始，因为第一个对象始终是stage顶级对象
                                let len1 = s._lastDpList[identifier].length;
                                let len2 = displayList.length;
                                len = len1 > len2 ? len1 : len2;
                                let isDiff = false;
                                let overEvent: MouseEvent;
                                let outEvent: MouseEvent;
                                for (let i = 1; i < len; i++) {
                                    if (!isDiff) {
                                        if (s._lastDpList[identifier][i] != displayList[i]) {
                                            //确定哪些有onMouseOver,哪些有onMouseOut
                                            isDiff = true;
                                            if (!s._ml[eLen]) {
                                                overEvent = new MouseEvent("onMouseOver");
                                                s._ml[eLen] = overEvent;
                                            } else {
                                                overEvent = s._ml[eLen];
                                                overEvent.type = "onMouseOver";
                                            }
                                            s._initMouseEvent(overEvent, cp, sp, identifier);
                                            eLen++;
                                            if (!s._ml[eLen]) {
                                                outEvent = new MouseEvent("onMouseOut");
                                                s._ml[eLen] = outEvent;
                                            } else {
                                                outEvent = s._ml[eLen];
                                                outEvent.type = "onMouseOut";
                                            }
                                            s._initMouseEvent(outEvent, cp, sp, identifier);
                                        }
                                    }
                                    if (isDiff) {
                                        if (s._lastDpList[identifier][i]) {
                                            //触发onMouseOut事件
                                            if (!outEvent["_pd"]) {
                                                d = s._lastDpList[identifier][i];
                                                if (d.hasEventListener("onMouseOut")) {
                                                    outEvent.currentTarget = d;
                                                    outEvent.target = s._lastDpList[identifier][len1 - 1];
                                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                                    outEvent.localX = lp.x;
                                                    outEvent.localY = lp.y;
                                                    d.dispatchEvent(outEvent);
                                                }
                                            }
                                        }
                                        if (displayList[i]) {
                                            //触发onMouseOver事件
                                            if (!overEvent["_pd"]) {
                                                d = displayList[i];
                                                if (d.hasEventListener("onMouseOver")) {
                                                    overEvent.currentTarget = d;
                                                    overEvent.target = displayList[len2 - 1];
                                                    lp = d.globalToLocal(cp, DisplayObject._bp);
                                                    overEvent.localX = lp.x;
                                                    overEvent.localY = lp.y;
                                                    d.dispatchEvent(overEvent);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        s._mp[s._mp.length] = cp;
                    }
                    if (item == "onMouseUp") {
                        delete s._mouseDownPoint[identifier];
                        delete s._lastDpList[identifier];
                    } else {
                        s._lastDpList[identifier] = displayList;
                    }
                }
            }
        }

        //禁止默认事件
        if (e.target.id == "cusCanvas") {
            if (s.isPreventDefaultEvent) {
                if ((e.type == "touchend") && (osType == "ios") && (s.iosTouchendPreventDefault)) {
                    e.preventDefault();
                }
                if ((e.type == "touchmove") || (e.type == "touchstart" && osType == "android")) {
                    e.preventDefault();
                }
            }
        }
    };

    /**
     * 设置舞台的对齐模式
     * @method setAlign
     * @private
     * @return {void}
     */
    private setAlign(): void {
        let s = this;
        let divH = s.divHeight * devicePixelRatio;
        let divW = s.divWidth * devicePixelRatio;
        let desH = s.desHeight;
        let desW = s.desWidth;
        s.anchorX = desW >> 1;
        s.anchorY = desH >> 1;
        //设备是否为竖屏
        let isDivH = divH > divW;
        //内容是否为竖屏内容
        let isDesH = desH > desW;
        let scaleY = 1;
        let scaleX = 1;
        s.x = (divW - desW) >> 1;
        s.y = (divH - desH) >> 1;
        if (s.autoSteering) {
            if (isDesH != isDivH) {
                let d = divH;
                divH = divW;
                divW = d;
            }
        }
        if (s._scaleMode != "noScale") {
            scaleY = divH / desH;
            scaleX = divW / desW;
            switch (s._scaleMode) {
                case "noBorder":
                    if (scaleX > scaleY) {
                        scaleY = scaleX;
                    } else {
                        scaleX = scaleY;
                    }
                    break;
                case "showAll":
                    if (scaleX < scaleY) {
                        scaleY = scaleX;
                    } else {
                        scaleX = scaleY;
                    }
                    break;
                case "fixedWidth":
                    scaleY = scaleX;
                    break;
                case "fixedHeight":
                    scaleX = scaleY;
                    break;
            }
        }

        s.scaleX = scaleX;
        s.scaleY = scaleY;
        // s.viewRect=new Rectangle();
        s.viewRect.x = (desW - divW / scaleX) >> 1;
        s.viewRect.y = (desH - divH / scaleY) >> 1;
        s.viewRect.width = desW - s.viewRect.x * 2;
        s.viewRect.height = desH - s.viewRect.y * 2;

        if (s.autoSteering) {
            if (isDesH == isDivH) {
                s.rotation = 0;
            } else {
                if (desH > desW) {
                    s.rotation = -90;
                } else {
                    s.rotation = 90;
                }
            }
        } else {
            s.rotation = 0;
        }
    };
    /**
     * 当舞台尺寸发生改变时,如果stage autoResize 为 true，则此方法会自己调用；
     * 如果设置stage autoResize 为 false 你需要手动调用此方法以更新界面.
     * 不管autoResize 的状态是什么，你只要侦听 了stage 的 Event.RESIZE 事件
     * 都可以接收到舞台变化的通知。
     * @method resize
     * @public
     * @since 1.0.0
     */
    public resize(): void {
        let s: Stage = this;
        let whObj //= s.getRootDivWH(s.rootDiv);
        if (s.rootDiv) {
            whObj = s.getRootDivWH(s.rootDiv);
        }
        //如果直接传的是canvas，直接取全屏幕的长宽
        else {
            whObj = { w: document.body.clientWidth, h: document.body.clientHeight }
        }

        s.divHeight = whObj.h;
        s.divWidth = whObj.w;
        s.renderObj.resize(s.divWidth, s.divHeight);
        s.setAlign();
        s.render();
    };

    public getBounds(): Rectangle {
        return this.viewRect;
    }

    /**
     * 要循环调用 flush 函数对象列表
     * @method allUpdateObjList
     * @static
     * @since 1.0.0
     * @type {Array}
     */
    private static allUpdateObjList: Array<any> = [];

    /**
     * 刷新所有定时器
     * @static
     * @private
     * @since 1.0.0
     * @method flushAll
     */
    static flushAll(): void {
        if (!Stage._pause) {
            let len = Stage.allUpdateObjList.length;
            for (let i = 0; i < len; i++) {
                Stage.allUpdateObjList[i] && Stage.allUpdateObjList[i].flush();
            }
        }
        requestAnimationFrame(Stage.flushAll);
    }

    /**
     * 添加一个刷新对象，这个对象里一定要有一个 flush 函数。
     * 因为一但添加，这个对象的 flush 函数会以stage的fps间隔调用
     * 如，你的stage是30fps 那么你这个对象的 flush 函数1秒会调用30次。
     * @method addUpdateObj
     * @param target 要循化调用 flush 函数的对象
     * @public
     * @static
     * @since
     */
    public static addUpdateObj(target: any): void {
        let isHave: boolean = false;
        let len = Stage.allUpdateObjList.length;
        for (let i = 0; i < len; i++) {
            if (Stage.allUpdateObjList[i] === target) {
                isHave = true;
                break;
            }
        }
        if (!isHave) {
            Stage.allUpdateObjList.unshift(target);
        }
    }

    /**
     * 移除掉已经添加的循环刷新对象
     * @method removeUpdateObj
     * @param target
     * @public
     * @static
     * @since 1.0.0
     */
    public static removeUpdateObj(target: any): void {
        let len = Stage.allUpdateObjList.length;
        for (let i = 0; i < len; i++) {
            if (Stage.allUpdateObjList[i] === target) {
                Stage.allUpdateObjList.splice(i, 1);
                break;
            }
        }
    }

    public destroy(): void {
        let s = this;
        Stage.removeUpdateObj(s);
        s.rootDiv = null;
        s._floatDisplayList = null;
        s.renderObj = null;
        s.viewRect = null;
        s._lastDpList = null;
        s._ml = null;
        super.destroy();
    }
}