import { SCALE_MODES, TEXT_ALIGN, TEXT_lINETYPE, VERTICAL_ALIGN, osType } from "../const";
import Texture from "../texture/Texture";
import { getRGBA, createCanvas, getEnv } from "../utils";
import { Rectangle } from "../math";
import Sprite from "../display/Sprite";
import { BaseTexture } from "../texture";


//文本canvas上xy的偏移量
const padding = 10;
/**
 * 到时有离屏canvas再修改，现在离屏canvasios有问题，且文本模糊
 * 继承Sprite，暂时发现，只需要切换bitmap和Sprite,TextField永远都是最新的，到时替换
 * 动态文本类,有时需要在canvas里有一个动态文本,能根据我们的显示内容来改变
 * @class TextFieldCon
 * @extends DisplayObject
 * @since 1.0.0
 * @public
 */
export class TextField extends Sprite {
    private static shareCanvas: HTMLCanvasElement;
    private static shareContext: CanvasRenderingContext2D;

    canvas: HTMLCanvasElement;
    context: CanvasRenderingContext2D;
    /**
     * 与其他类不同，用了Boolean，再考虑
     */
    dirty: boolean;

    offsetX: number;
    offsetY: number;
    constructor() {
        super();
        this._instanceType = "TextField";
        //ios直接
        // if (osType == "ios") {
        var canvas = createCanvas()
        // canvas.width = 3;
        // canvas.height = 3;
        // if (osType == "ios") {
        canvas.width = canvas.height = 3;
        // } else {//现在只能用canvas2d渲染，所以不能用imageData了，等修复了安卓canvas尺寸问题再改
        //     canvas.width = 300;
        //     canvas.height = 150;
        // }
        this.texture = Texture.fromCanvas(canvas, "textCanvas");
        this.canvas = canvas;
        this.context = canvas.getContext("2d");
        // }
        // //安卓的不能改变离屏canvas的尺寸，所以用750*750的，取imageData
        // else {
        //     if (!TextField.shareCanvas) {
        //         TextField.shareCanvas = createCanvas();
        //         TextField.shareCanvas.width = TextField.shareCanvas.height = 750;
        //         TextField.shareContext = TextField.shareCanvas.getContext("2d");
        //     }
        //     var baseTexture = new BaseTexture({
        //         data: [],
        //         width: 0,
        //         height: 0,
        //         type: "text",
        //         path: null
        //     });
        //     this.texture = new Texture(baseTexture);

        //     this.canvas = TextField.shareCanvas;
        //     this.context = TextField.shareContext;
        // }
        //baseTexture已自动缓存，把texture也缓存，key textCanvas+num  和baseTexture的一致
        Texture.addToCache(this.texture, this.texture.baseTexture.textureCacheIds[0]);

        this.dirty = true;
    }

    /**
     * @property textAlpha
     * @since 2.0.0
     * @public
     */
    public set textAlpha(value: number) {
        if (this._textAlpha != value) {
            this._textAlpha = value;
            this.dirty = true;
        }
    }

    public get textAlpha(): number {
        return this._textAlpha;
    }
    private _textAlpha: number = 1;

    /**
     * 文本的水平对齐方式 left center right
     * 设置过textHeight才有效，如果是多行的，对排版有作用
     * @property textAlign
     * @public
     * @since 1.0.0
     * @type {string}
     * @default left
     */
    public set textAlign(value: TEXT_ALIGN) {
        if (this._textAlign != value) {
            this._textAlign = value;
            this.dirty = true;
        }
    }

    public get textAlign(): TEXT_ALIGN {
        return this._textAlign;
    }
    private _textAlign: TEXT_ALIGN = TEXT_ALIGN.LEFT;

    /**
     * 垂直对齐方式 
     * 设置过textHeight才有效
     */
    public set verticalAlign(value: VERTICAL_ALIGN) {
        if (this._verticalAlign != value) {
            this._verticalAlign = value;
            this.dirty = true;
        }
    }

    public get verticalAlign(): VERTICAL_ALIGN {
        return this._verticalAlign;
    }
    private _verticalAlign: VERTICAL_ALIGN = VERTICAL_ALIGN.UP;

    /**
     * 文本的宽，
     * @property textWidth
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 0
     */
    public set textWidth(value: number) {
        if (this._textWidth != value) {
            this._textWidth = value;
            this.dirty = true;
        };
    }
    public get textWidth(): number {
        if (this._textWidth) {
            //有就这个
            return this._textWidth
        } else {
            //没有就计算出的给width，还是
            this.updateText();
            return this.width - padding * 2;
        }
    }
    private _textWidth: number = 0;

    /**
     * 文本的行高，设置过能进行垂直适配，
     * 文本超出行高会被裁切
     * @property textHeight
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 0
     */
    public set textHeight(value: number) {
        if (this._textHeight != value) {
            this._textHeight = value;
            this.dirty = true;
        }
    }

    public get textHeight(): number {
        if (this._textHeight) {
            //有就这个
            return this._textHeight
        } else {
            //没有就计算出的给height，还是
            this.updateText();
            return this.height - padding * 2
        }
    }
    private _textHeight: number = 0;

    /**
     * 行间距
     * @property lineSpacing
     * @public
     * @since 1.0.0
     * @param {number} value
     */
    public set lineSpacing(value: number) {
        if (this._lineSpacing != value) {
            this._lineSpacing = value;
            this.dirty = true;
        };
    }
    public get lineSpacing(): number {
        return this._lineSpacing;
    }
    private _lineSpacing: number = 14;

    /**
     * 文本类型,单行还是多行 single multi
     * @property lineType
     * @public
     * @since 1.0.0
     * @type {string} 两种 single和multi
     * @default single
     */
    public set lineType(value: TEXT_lINETYPE) {
        if (this._lineType != value) {
            this._lineType = value;
            this.dirty = true;
        };
    }
    public get lineType(): TEXT_lINETYPE {
        return this._lineType;
    }
    private _lineType: TEXT_lINETYPE = TEXT_lINETYPE.SINGLE;
    /**
     * 文本内容
     * @property text
     * @type {string}
     * @public
     * @default ""
     * @since 1.0.0
     */
    public set text(value: string) {
        if (this._text != value) {
            this._text = value;
            this.dirty = true;
        };
    }

    public get text(): string {
        return this._text;
    }
    private _text: string = "";
    /**
     * 文本的css字体样式
     * @property font
     * @public
     * @since 1.0.0
     * @type {string}
     * @default 12px Arial
     */
    public set font(value: string) {
        if (this._font != value) {
            this._font = value;
            this.dirty = true;
        };
    }

    public get font(): string {
        return this._font;
    }
    private _font: string = "Arial";
    /**
     * 文本的size
     * @property size
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 12
     */
    public set size(value: number) {
        if (this._size != value) {
            this._size = value;
            this.dirty = true;
        };
    }

    public get size(): number {
        return this._size;
    }
    private _size: number = 12;
    /**
     * 文本的填充颜色值
     * @property fillColor
     * @type {string}
     * @public
     * @since 1.0.0
     * @default #fff
     */
    public set fillColor(value: string) {
        if (this._fillColor != value) {
            this._fillColor = value;
            this.dirty = true;
        };
    }

    public get fillColor(): string {
        return this._fillColor;
    }
    private _fillColor: string = "#ffffff";

    /**
     * 文本的描边颜色值
     * @property strokeColor
     * @type {string}
     * @public
     * @since 1.0.0
     * @default #fff
     */
    public set strokeColor(value: string) {
        if (this._strokeColor != value) {
            this._strokeColor = value;
            this.dirty = true;
        };
    }

    public get strokeColor(): string {
        return this._strokeColor;
    }
    private _strokeColor: string = "#ffffff";
    /**
     * 文本描边宽度,为0则不描边
     * @property stroke
     * @public
     * @since
     * @default 0
     * @type {number}
     */
    public set stroke(value: number) {
        if (this._stroke != value) {
            this._stroke = value;
            this.dirty = true;
        };
    }

    public get stroke(): number {
        return this._stroke;
    }
    private _stroke: number = 0;

    /**
     * 文本是否倾斜
     * @property italic
     * @public
     * @since
     * @default false
     * @type {boolean}
     */
    public set italic(value: boolean) {
        if (this._italic != value) {
            this._italic = value;
            this.dirty = true;
        };
    }

    public get italic(): boolean {
        return this._italic;
    }
    private _italic: boolean = false;
    /**
     * 文本是否加粗
     * @property bold
     * @public
     * @since
     * @default false
     * @type {boolean}
     */
    public set bold(value: boolean) {
        if (this._bold != value) {
            this._bold = value;
            this.dirty = true;
        };
    }
    public get bold(): boolean {
        return this._bold;
    }
    public _bold: boolean = false;
    /**
     * 设置或获取是否有边框
     * @property property
     * @param {boolean} show true或false
     * @public
     * @since 1.0.6
     */
    public set border(value: boolean) {
        if (this._border != value) {
            this._border = value;
            this.dirty = true;
        };
    }

    public get border(): boolean {
        return this._border;
    }
    private _border: boolean = false;

    /**
     * 设置文本在canvas里的渲染样式
     * @method _prepContext
     * @param ctx
     * @private
     * @since 1.0.0
     */
    private _prepContext(ctx: any): void {
        let s = this;
        let font: any = s.size || 12;
        font += "px ";
        font += s.font;
        //font-weight:bold;font-style:italic;
        if (s._bold) {
            font = "bold " + font;
        }
        if (s._italic) {
            font = "italic " + font;
        }
        ctx.font = font;
        ctx.textAlign = s._textAlign || TEXT_ALIGN.LEFT;
        //暂时没开放
        ctx.textBaseline = "top";
        ctx.fillStyle = getRGBA(s._fillColor, s._textAlpha)
    }
    /**
     * 获取当前文本中单行文字的宽，注意是文字的不是文本框的宽
     * 暂不用，可能有问题
     * @method getTextWidth
     * @param {number} lineIndex 获取的哪一行的高度 默认是第1行
     * @since 2.0.0
     * @public
     * @return {number}
     */
    public getTextWidth(lineIndex: number = 0): number {
        let s = this;
        s.updateText();
        // let can = s.canvas;
        let ctx = s.context;
        let obj: any = ctx.measureText(s.realLines[lineIndex]);
        return obj.width;
    }
    /**
     * @property _lines 获取当前文本行数
     * @type {number}
     * @public
     * @readonly
     * @since 2.0.0
     */
    get lines(): number {
        return this.realLines.length;
    }
    /**
     * 获取文本宽
     * @method _getMeasuredWidth
     * @param text
     * @return {number}
     * @private
     * @since 1.0.0
     */
    private _getMeasuredWidth(text: string): number {
        //如果不是淘宝环境，就用canvas的api measureText
        if (getEnv() == "web") return this.context.measureText(text).width
        //暂时没修复，用最简单的量尺寸UuUuAaaA
        //中文
        var patternCh = new RegExp("[\u4E00-\u9FA5]+");
        //中文标点，匹配这些中文标点符号 。 ？ ！ ， 、 ； ： “ ” ‘ ' （ ） 《 》 〈 〉 【 】 『 』 「 」 ﹃ ﹄ 〔 〕 … — ～ ﹏ ￥
        var patternChB = /[\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]/;
        //英文，
        var patternEn = new RegExp("[A-Za-z]+");
        var size = this.size;
        var width = 0;
        for (var i = 0; i < text.length; i++) {
            var str = text[i];
            if (patternCh.test(str) || patternChB.test(str)) {
                width += size;
            } else {
                width += size * 4 / 7;
            }
        }
        return width
    }
    private realLines: any = []; private callback;
    /**
     * 更新文本，主要重画canvas，回调是很有问题的
     */
    public updateText(/*callback?*/): void {
        // if (callback) this.callback = callback;
        // let backupCanvasContext = getBackupCanvasContext();
        // if (!backupCanvasContext) return
        // if (backupCanvasContext["isBusy"]) return;
        let s: TextField = this;
        if (!s.dirty) {
            // this.callback && this.callback();
            // this.callback = null
            return;
        }
        s.dirty = false;
        //如果没有文本
        if (!s._text) {
            // if (osType == "ios") {
            s.canvas.width = 0;
            s.canvas.height = 0;
            // } else {//暂时不能用sourceData形式，所以和上面效果一样
            //     s.texture.baseTexture.source.width = 0;
            //     s.texture.baseTexture.source.height = 0;
            // }
            s._localBoundsSelf.clear();
            s.anchorTexture = { x: 0, y: 0 };
            s.texture.update()
            return
        }
        s._text += "";
        let can = s.canvas;
        let ctx: CanvasRenderingContext2D = /*backupCanvasContext*/s.context;
        // ctx.save();
        let hardLines: any = s._text.toString().split(/(?:\r\n|\r|\n)/);
        let realLines: any = [];
        s.realLines = realLines;
        s._prepContext(ctx);//因为不用canvas的api量文本宽度，所以这里执行不重要

        let textWidth = s._textWidth;
        // let lineH = s._lineSpacing + s.size;
        //单行文本时
        if (s._text.indexOf("\n") < 0 && //没有换行符
            s._text.indexOf("\r") < 0 && //没有换行符
            s._text.indexOf("\r\n") < 0 && //没有换行符
            s.lineType == TEXT_lINETYPE.SINGLE //确定单行
        ) {
            realLines[realLines.length] = hardLines[0];
            let str = hardLines[0];
            let lineW = s._getMeasuredWidth(str);
            //如果没设置过textWidth就取lineW
            textWidth = textWidth || lineW;
            //如果设置过textWidth的。截取文本
            if (lineW > textWidth) {
                let w = s._getMeasuredWidth(str[0]);
                let lineStr = str[0];
                let wordW = 0;
                let strLen = str.length;
                for (let j = 1; j < strLen; j++) {
                    wordW = s._getMeasuredWidth(str[j])//ctx.measureText(str[j]).width;
                    w += wordW;
                    if (w > textWidth) {
                        realLines[0] = lineStr;
                        break;
                    } else {
                        lineStr += str[j];
                    }
                }
            }
        } else {
            //textWidth取每行最大值，如果没设置过textWidth
            if (!textWidth) {
                for (let i = 0, l = hardLines.length; i < l; i++) {
                    let str = hardLines[i];
                    if (!str) continue;
                    textWidth = Math.max(s._getMeasuredWidth(str), textWidth);
                }
            }
            for (let i = 0, l = hardLines.length; i < l; i++) {
                let str = hardLines[i];
                if (!str) continue;
                let w = s._getMeasuredWidth(str[0]);
                let lineStr = str[0];
                let wordW = 0;
                let strLen = str.length;
                for (let j = 1; j < strLen; j++) {
                    wordW = s._getMeasuredWidth(str[j])//ctx.measureText(str[j]).width;
                    w += wordW;
                    if (w > textWidth) {
                        realLines[realLines.length] = lineStr;
                        lineStr = str[j];
                        w = wordW;
                    } else {
                        lineStr += str[j];
                    }
                }
                realLines[realLines.length] = lineStr;
            }
        }
        // let maxH = lineH * realLines.length;
        var trueHeight: number = s.size * realLines.length + s._lineSpacing * (realLines.length - 1);
        let maxH = s._textHeight || trueHeight;
        let maxW = textWidth;
        let tx = 0;
        if (s._textAlign == TEXT_ALIGN.CENTER) {
            tx = maxW * 0.5;
        } else if (s._textAlign == TEXT_ALIGN.RIGHT) {
            tx = maxW;
        }
        let canWidth = maxW + padding * 2;
        let canHeight = maxH + padding * 2;
        can.width = canWidth
        can.height = canHeight
        ctx.setTransform(1, 0, 0, 1, 0, 0);//在不能修改尺寸的时候，否则尺寸改变，上下文会初始化
        ctx.clearRect(0, 0, can.width, can.height);//安卓貌似无效，文案重叠了再处理，或者等修复了尺寸问题就好了
        if (s.border) {
            ctx.beginPath();
            ctx.strokeStyle = "#000";
            ctx.lineWidth = 1;
            ctx.strokeRect(padding + 0.5, padding + 0.5, maxW, maxH);
            ctx.closePath();
        }
        ctx.setTransform(1, 0, 0, 1, tx + padding, padding/* - 10*/);
        s._prepContext(ctx);
        let lineH = s._lineSpacing + s.size;
        //如果有_textHeight,就需要应用竖直对齐
        var upY: number = 0;
        if (s._textHeight) {
            //跟trueHeight比较
            if (s._verticalAlign == VERTICAL_ALIGN.MIDDLE) {
                upY = (s._textHeight - trueHeight) * 0.5;
            } else if (s._verticalAlign == VERTICAL_ALIGN.DOWN) {
                upY = s._textHeight - trueHeight;
            }
        }
        //@ts-ignore
        my && (upY -= 4);
        for (let i = 0; i < realLines.length; i++) {
            let ox = 0;
            //@ts-ignore 现在貌似小程序的textAlign有点问题，如果修复了再说
            // if (my) ox = - tx;//移回去，已经修复，注释掉吧
            if (s.stroke) {
                ctx.strokeStyle = s.strokeColor;
                ctx.lineWidth = s.stroke * 2;
                ctx.strokeText(realLines[i], ox, upY + i * lineH/*, maxW*/);
            }
            ctx.fillText(realLines[i], ox, upY + i * lineH/*, maxW*/);//考虑去掉这个maxW
        }
        //offset用_anchorTexture代替
        s.offsetX = -padding;
        s.offsetY = -padding;
        // console.log(can)
        this.anchorTexture = { x: (padding + 0.5) / canWidth, y: padding / canHeight }
        // if (osType == "ios") {
        s.texture.update();
        s._onTextureUpdate();
        // } else {
        //     var imgData = ctx.getImageData(0, 0, canWidth, canHeight)
        //     var data = {
        //         data: new Uint8Array(imgData.data),
        //         width: canWidth,
        //         height: canHeight,
        //         type: "text",
        //         path: null
        //     }
        //     s.texture.baseTexture._sourceChange(data);
        //     s._onTextureUpdate();
        // }

    }

    //暂时没用
    _renderCanvas(renderer) {
        this.updateText();
        super._renderCanvas(renderer);
    }
    _renderWebGL(renderer) {
        this.updateText();
        super._renderWebGL(renderer)
    }

    public destroy(): void {
        this.canvas = null;
        this.context = null;
        super.destroy();
        //todo
    }
}
