import { Event } from "../events/Event";
import { DisplayObject } from "./DisplayObject";
// import { devicePixelRatio } from "../const";
/**
 * 此类对于需要在canvas上放置html其他类型元素的时候非常有用<br/>
 * 比如有时候我们需要放置一个注册,登录或者其他的内容.这些内容包含了输入框<br/>
 * 或者下拉框什么的,无法在canvas里实现,但这些元素又跟canvas里面的元素<br/>
 * 位置,大小,缩放对应.就相当于是一个显示对象一样。可以随意设置他的<br/>
 * 属性,那么将你的html元素通过此类封装成显示对象再合适不过了
 * 不能用于容器
 * 注意canvas所在标签和自身htmlElement样式position设置为absolute
 * @class FloatDisplay
 * @extends DisplayObject
 * @public
 * @since 1.0.0
 */
export class FloatDisplay extends DisplayObject {
    /**
     * 需要封装起来的html元素的引用。你可以通过这个引用来调用或设置此元素自身的属性方法和事件,甚至是样式
     * @property htmlElement
     * @public
     * @since 1.0.0
     * @type{HtmlElement}
     */
    public htmlElement: any = null;
    /**
     * 是否已经添加了舞台事件
     * @property _isAdded
     * @since 1.0.0
     * @type {boolean}
     * @private
     */
    private _isAdded: boolean = false;

    /**
     * 记录是否需要修改位置矩阵
     */
    private _transformID: number;
    /**
     * 构造函数
     * @method FloatDisplay
     * @since 1.0.0
     * @public
     * @example
     *      var floatDisplay = new FloatDisplay();
     *      floatDisplay.init(document.getElementById('aaa'));
     *      s.addChild(floatDisplay);
     *
     * <p><a href="" target="_blank">测试链接</a></p>
     * 
     * @example
     *  //创建悬浮的html元素
     *  var section = document.createElement('section');
     *   section.id = "rule";
     *   section.style.overflowX = "hidden";
     *   section.style.overflowY = "auto";
     *   section.style.width = w + "px";
     *   section.style.height = h + "px";
     *   section.style.lineHeight = lh + "px";
     *   section.style.fontFamily = '微软雅黑';
     *   section.style.fontSize = fs + 'px';
     *   section.style.color = "#ffffff";
     *   section.style.position = "absolute";
     *   //创建Floatview 把我们要悬浮的元素封装进去
     *   var rule = new FloatDisplay();
     *   stage.addChild(rule);
     *   rule.x = ox;
     *   rule.y = oy;
     *   rule.init(section);
     *   section.innerHTML = DataManager.ins.getData("ajaxElement").data.rule;
     *
     */
    public constructor() {
        super();
        let s = this;
        s._instanceType = "FloatDisplay";
        s.addEventListener(Event.REMOVED_FROM_STAGE, function (e: Event) {
            if (s.htmlElement) {
                s.htmlElement.style.display = "none";
            }
            //移除updateStyle监听
            s.stage.removeEventListener(Event.ENTER_FRAME, s.updateStyle, s)
        });
        s.addEventListener(Event.ADDED_TO_STAGE, function (e: Event) {
            if (s.htmlElement) {
                let style = s.htmlElement.style;
                if (!s._isAdded) {
                    s._isAdded = true;
                    if (s.stage["rootDiv"]) {
                        s.stage["rootDiv"].insertBefore(s.htmlElement, s.stage["rootDiv"].childNodes[0]);
                    }
                    //没有div直接加在body里吧
                    else {
                        document.body.appendChild(s.htmlElement)
                    }
                } else {
                    if (s.htmlElement && s.visible) {
                        style.display = "block";//"inline-block"
                    }
                }
            }
            //在stage上监听循环，修改显示
            s.stage.addEventListener(Event.ENTER_FRAME, s.updateStyle, s)
        });

        this._transformID = -1;
    }

    /**
     * 初始化方法,htmlElement 一定要设置width和height样式,并且一定要用px单位
     * @method init
     * @public
     * @since 1.0.0
     * @param {HtmlElement} htmlElement 需要封装起来的html元素的引用。你可以通过这个引用来调用或设置此元素自身的属性方法和事件,甚至是样式
     */
    public init(htmlElement: any): void {
        let s = this;
        let she: any;
        if (typeof (htmlElement) == "string") {
            she = document.getElementById(htmlElement);
        } else if (htmlElement._instanceType == "Video") {
            she = htmlElement.media;
        } else {
            she = htmlElement;
        }
        //原先有的先移除
        if (s.htmlElement) s.removeHtmlElement();
        let style = she.style;
        style.position = "absolute";
        style.display = "none";
        style.transformOrigin = style.WebkitTransformOrigin = "0 0 0";
        let ws = s.getStyle(she, "width");
        let hs = s.getStyle(she, "height");
        let w = 0, h = 0;
        if (ws.indexOf("px")) {
            w = parseInt(ws);
        }
        if (hs.indexOf("px")) {
            h = parseInt(hs);
        }
        // s._bounds.width = w;
        // s._bounds.height = h;
        s._localBoundsSelf.width = w;
        s._localBoundsSelf.height = h;
        s.htmlElement = she;
        //如果原先在舞台上，加入，是否显示下一帧吧
        if (s.stage) {
            s._isAdded = true;
            if (s.stage["rootDiv"]) {
                s.stage["rootDiv"].insertBefore(s.htmlElement, s.stage["rootDiv"].childNodes[0]);
            }
            //没有div直接加在body里吧
            else {
                document.body.appendChild(s.htmlElement)
            }
        }
    }

    /**
     * @method getStyle
     * @param {HTMLElement} elem
     * @param cssName
     * @return {any}
     */
    private getStyle(elem: HTMLElement, cssName: any): any {
        //如果该属性存在于style[]中，则它最近被设置过(且就是当前的)
        if (elem.style[cssName]) {
            return elem.style[cssName];
        }
        if (document.defaultView && document.defaultView.getComputedStyle) {
            //它使用传统的"text-Align"风格的规则书写方式，而不是"textAlign"
            cssName = cssName.replace(/([A-Z])/g, "-$1");
            cssName = cssName.toLowerCase();
            //获取style对象并取得属性的值(如果存在的话)
            let s = document.defaultView.getComputedStyle(elem, "");
            return s && s.getPropertyValue(cssName);
        }
        return null;
    }

    /**
     * 考虑放到stage里，因为父级的visible修改不会调用updateStyle
     * @method updateStyle
     * @public
     * @since 1.1.4
     */
    private updateStyle(): void {
        let s = this;
        let o = s.htmlElement;
        if (o) {
            let style = o.style;
            let visible = s.visible;
            //还得考虑是否在stage里
            if (!s.stage) {
                visible = false
            }
            if (visible) {
                let parent = s.parent;
                while (parent) {
                    if (!parent.visible) {
                        visible = false;
                        break;
                    }
                    parent = parent.parent;
                }
            }

            let show = visible ? "block" : "none";
            if (show != style.display) {
                style.display = show;
            }
            if (visible) {
                if (this._transformID != this.transform._worldID) {
                    this._transformID = this.transform._worldID
                    let mtx = s.transform.worldMatrix;
                    let d = s.stage["_dpi"] || s.stage["dpi"]//devicePixelRatio;//不用设备的,改成stage的
                    style.transform = style.webkitTransform = "matrix(" + (mtx.a / d).toFixed(4) + "," + (mtx.b / d).toFixed(4) + "," + (mtx.c / d).toFixed(4) + "," + (mtx.d / d).toFixed(4) + "," + (mtx.tx / d).toFixed(4) + "," + (mtx.ty / d).toFixed(4) + ")";
                }
                style.opacity = s._worldAlpha;
            }
        }
    }
    /**
     * 移除htmlElement
     */
    private removeHtmlElement(): void {
        let s = this;
        let elem = s.htmlElement;
        if (elem) {
            elem.style.display = "none";
            if (elem.parentNode) {
                elem.parentNode.removeChild(elem);
            }
            s._isAdded = false;
            s.htmlElement = null;
        }
    }
    //放在stage的帧循环的监听里了
    // public renderCanvas() {
    //     this.updateStyle();
    // }
    // public renderWebGL() {
    //     this.updateStyle();
    // }

    public destroy(): void {
        super.destroy();
        this.removeHtmlElement();
    }
}
