Engine.DrawableText = class extends PIXI.Sprite
{	
	constructor(text, fontFamily, fontSize, align, spacing)
	{
		super();

        this.style = new PIXI.TextStyle({
          fontFamily: "Verdana",
          fontSize: 12,
          fill: "white",
          resolution: 2,
        });

        this.normalText = new PIXI.Text();
        this.multiText = null; // lazy
        this.text.style = this.style;
        this.addChild(this.text);
        this.isMultiStyleText = false;
        this.name = "DrawableText";

        this.text.text = "";//"text";
        this.styleTags = {"default": {}, "b": {fontStyle: "bold"}, "ml": {fontStyle: "italic", fill: "#ff8888"},"ms": {fontStyle: "italic", fill: "#4488ff"} };

		if (typeof text === 'string')
		{
			this.setText(text, fontFamily, fontSize, align, spacing);
		}

        this.interactiveChildren = false;
        //this.interactive = false;
	}

    get text()
    {
        if (this.isMultiStyleText) return this.multiText;
        else return this.normalText;
    }

    setTint(color)
    {
        this.textColor = color;
    }

    get tint()
    {
        return this.textColor;
    }
    set tint(color)
    {
        this.textColor = color;
    }

    get textColor() { return this.style.fill; }
    set textColor(value)
    { 
        if (this.style != null && value !== undefined)
        {
            if (value.getHex) value = value.getHex();
            this.style.fill = value;
            this.text.text = this.text.text;
        }
    }

    clearOverrideColors()
    {
        if (this.isMultiStyleText)
        {
            this.removeChild(this.text);
            this.isMultiStyleText = false;
            this.addChild(this.text);
            for (var tag in Object.keys(this.styleTags.default))
            {
                this.style[tag] = this.styleTags.default[tag];
            }
            this.styleTags.default = {};
            delete this.styleTags.highlight;
        }

        this.tint = Colors.white;
        //this.fill = "white";
    }

    changeTextRangeColor()
    {
        //TODO
    }

    updateVertexColors()
    {
        //TODO
    }

    getFont()
    {
        return this.style.fontFamily;
    }

    getFontSize()
    {
        return this.style.fontSize;
    }

    getAlignment()
    {
        return this.style.align;
    }

    setGameObjectName(name)
    {
        this.name = name;
    }

    get x() { return super.x; }
    set x(value) { super.x = Math.round(value); }

    get y() { return super.y; }
    set y(value) { super.y = Math.round(value); }

    get width() { return this.text.width * Math.abs(this.scale.x); }
    get height() 
    {
        if (this.text.text == " ") { return 0; } // maintain parity with unity 
        return this.text.height *  Math.abs(this.scale.y); //1.05 to maintain parity
    }
    get textLineHeight() { return this.height / this.numTextLines; }

    get textAreaWidth() { return this.style.wordWrapWidth ? this.style.wordWrapWidth : 0; }
    set textAreaWidth(value)
    {
        if (value == this.style.wordWrapWidth) return;

        this.style.wordWrapWidth = value;
        this.style.wordWrap = true;
        this.style.breakWords = true;

        if (this.styleTags.default !== undefined)
        {
            this.styleTags.default.wordWrapWidth = value;
            this.styleTags.default.wordWrap = true;
            this.styleTags.default.breakWords = true;
        }
        
        this.adjustForCentering();
    }

    get numTextLines()
    {  
        var textMetrics = PIXI.TextMetrics.measureText(this.text.text, this.style);
        return textMetrics.lines.length; 
    }

    getText()
    {
        if (this.text.text == " ") return "";
        return this.text.text;
    }

    setText(text, fontFamily, fontSize, align, spacing)
    {
		//if (Engine.Drawable.fastRenderMode) text = "";
        if (fontFamily === undefined) fontFamily = "Verdana";
        if (fontSize === undefined) fontSize = 12;
        if (align === undefined) align = "left";
        if (spacing === undefined) spacing = 1;

        // early exit
        if (text == this.text.text &&
            fontFamily == this.style.fontFamily &&
            fontSize == this.style.fontSize &&
            align == this.style.align) return;

        this.style.fontFamily = fontFamily;
        this.style.fontSize = fontSize;
        this.style.align = align;
        this.text.text = text;
        this.text.dirty = true;

        this.adjustForCentering();
    }

    setTextInHeight(text, height, fontFamily, fontSize, align, spacing)
    {
        if (align === undefined) align = "left";
        if (spacing === undefined) spacing = 1;

        // early exit
        if (text == this.text.text &&
            fontFamily == this.style.fontFamily &&
            fontSize == this.style.fontSize &&
            align == this.style.align &&
            height == this.style.scaleHeight) return;

        this.style.align = align;
        this.text.text = text;
        this.text.dirty = true;

        this.scaleTextToFit(null, height, fontFamily, fontSize);
    }

    setTextInWidth(text, width, fontFamily, fontSize, align, spacing)
    {
        if (align === undefined) align = "left";
        if (spacing === undefined) spacing = 1;

        // early exit
        if (text == this.text.text &&
            fontFamily == this.style.fontFamily &&
            fontSize == this.style.fontSize &&
            align == this.style.align &&
            width == this.style.scaleWidth) return;

        this.style.align = align;
        this.text.text = text;
        this.text.dirty = true;

        this.scaleTextToFit(width, null, fontFamily, fontSize);
    }

    setTextInWidthHeight(text, width, height, fontFamily, fontSize, align, spacing)
    {
        if (align === undefined) align = "left";
        if (spacing === undefined) spacing = 1;

        // early exit
        if (text == this.text.text &&
            fontFamily == this.style.fontFamily &&
            fontSize == this.style.fontSize &&
            align == this.style.align &&
            width == this.style.scaleWidth &&
            height == this.style.scaleHeight) return;

        this.style.align = align;
        this.text.text = text;
        this.text.dirty = true;

        this.scaleTextToFit(width, height, fontFamily, fontSize);
    }

    setTextWithHighlightFormating(text, highlightColor, fontFamily, fontSize, align, spacing)
    {
		//if (Engine.Drawable.fastRenderMode) text = "";
        if (fontFamily === undefined) fontFamily = "Verdana";
        if (fontSize === undefined) fontSize = 12;
        if (align === undefined) align = "left";
        if (spacing === undefined) spacing = 1;

        highlightColor = highlightColor.getHex();
        if (this.styleTags.highlight == undefined) this.styleTags.highlight = {};
        this.styleTags.highlight.fill = highlightColor; 

        text = text.replace(/{/g, "<highlight>");
        text = text.replace(/}/g, "</highlight>");

        // early exit
        if (text == this.text.text &&
            fontFamily == this.style.fontFamily == this.styleTags.default.fontFamily &&
            fontSize == this.style.fontSize == this.styleTags.default.fontSize &&
            align == this.style.align == this.styleTags.default.align &&
            highlightColor == this.style.fill == this.styleTags.default.fill) return;

        this.setMultiStyleText(text, fontFamily, fontSize, align);
    }

    setTextWithCustomColors(text, colors, fontFamily, fontSize, align, spacing)
    {
		//if (Engine.Drawable.fastRenderMode) text = "";
        if (fontFamily === undefined) fontFamily = "Verdana";
        if (fontSize === undefined) fontSize = 12;
        if (align === undefined) align = "left";
        if (spacing === undefined) spacing = 1;

		if (!colors || typeof colors !== 'object') colors = {};

		if (!colors['base']) colors['base'] = Colors.white;

		for (let name in colors)
		{
			let hex = colors[name].getHex();
			if (this.styleTags[name] == undefined) this.styleTags[name] = {};
			this.styleTags[name].fill = hex; 
		}

		text = '<base>' + text + '</base>';

        // early exit
        if (text == this.text.text &&
            fontFamily == this.style.fontFamily == this.styleTags.default.fontFamily &&
            fontSize == this.style.fontSize == this.styleTags.default.fontSize &&
            align == this.style.align == this.styleTags.default.align) return;

        this.setMultiStyleText(text, fontFamily, fontSize, align);
    }

    reSetText()
    {
        this.setText(this.getText(), this.getFont(), this.getFontSize(), this.getAlignment());
    }
	
	recenterText()
	{
		this.setText(this.getText(), this.getFont(), this.getFontSize(), "center");
	}

    scaleTextToFitHeight(height, fontFamily, fontSize)
    {
        // early exit
        // if (fontFamily == this.style.fontFamily &&
        //     fontSize == this.style.fontSize &&
        //     height == this.style.scaleHeight) return;

        this.scaleTextToFit(null, height, fontFamily, fontSize);
    }

    scaleTextToFit(width, height, fontFamily, fontSize)
    {
        this.style.scaleWidth = width;
        this.style.scaleHeight = height;
        this.style.fontFamily = fontFamily;
        var fits = false;
        while(!fits && fontSize > 4)
        {
            this.style.fontSize = fontSize;
            var fitsWidth = (width == null || width > this.text.width);
            var fitsHeight = (height == null || height > this.text.height);
            fits = fitsWidth && fitsHeight;
            fontSize--;
        }

        this.text.dirty = true;

        this.adjustForCentering();
    }

    adjustForCentering()
    {
        if (this.style.align == "center")
        {
            if (this.style.wordWrap)
            {
                this.text.x = Math.floor((this.style.wordWrapWidth - this.text.width) * 0.5);
            }
            else
            {
                this.text.x = (this.textAreaWidth - this.text.width) * 0.5;
            }
        } 
        else if (this.style.align == "right")
        {
            if (this.style.wordWrap)
            {
                this.text.x = Math.floor(this.style.wordWrapWidth - this.text.width);
            }
            else
            {
                this.text.x = this.textAreaWidth - this.text.width;
            }
        }
        else 
        {
            this.text.x = 0;
        }
    }

    setMultiStyleText(text, fontFamily, fontSize, align)
    {
		if (Engine.Drawable.fastRenderMode) text = "";

        this.style.fontFamily = fontFamily;
        this.style.fontSize = fontSize;
        this.style.align = align;

        this.styleTags.default.fontFamily = this.style.fontFamily;
        this.styleTags.default.fontSize = this.style.fontSize;
        this.styleTags.default.align = this.style.align;
        this.styleTags.default.resolution = this.style.resolution;
        this.styleTags.default.fill = this.style.fill;
        this.styleTags.default.wordWrapWidth = this.style.wordWrapWidth;
        this.styleTags.default.wordWrap = this.style.wordWrap;
        this.styleTags.default.breakWords = this.style.breakWords;

        if (this.multiText == null)
        {
            this.multiText = new MultiStyleText(text, this.styleTags);
        }

        this.removeChild(this.text);
        this.isMultiStyleText = true;
        this.addChild(this.text);

        this.text.styles = this.styleTags;
        this.text.style = this.style;
        this.text.text = text;
        this.text.dirty = true;

        this.adjustForCentering();
    }

    removeFromParent()
    {
        if (this.parent != null) this.parent.removeChild(this);
    }
    
    get hasParent() { return this.parent != null; }

    set fill(value)
    {
        this.style.fill = value;
    }

    setDropShadow(distance, color)
    {
        if (distance === undefined) distance = 1;
        if (color === undefined) color = Colors.black;

        this.style.dropShadow = true;
        this.style.dropShadowDistance = distance;
        this.style.dropShadowColor = color;
    }

    setOutline(thickness, color)
    {
        if (thickness === undefined) thickness = 1;
        if (color === undefined) color = Colors.white;

        this.style.strokeThickness = thickness;
        this.style.stroke = color;
    }

    drawDebug()
    {
        if (this.graphics === undefined) this.graphics = new PIXI.Graphics();
        this.addChildAt(this.graphics, 0);
        this.graphics.clear();
        this.graphics.beginFill(0xFFFFFF, 0.5);

        var width = this.textAreaWidth > 0 ? this.textAreaWidth : this.text.width;
        var height = this.text.height;

        this.graphics.drawRect(0, 0, width, height);
    }

}

Engine.FontStyle = class
{
    constructor(fontFamily, fontSize, align)
    {
        if (align === undefined) align = "left";

        this.family = fontFamily;
        this.size = fontSize;
        this.align = align;
    }
}