package electrosphere.renderer.ui.elements;

import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.model.Material;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.ui.elementtypes.DrawableElement;
import electrosphere.renderer.ui.events.Event;
import electrosphere.renderer.ui.font.Font;
import org.joml.Vector3f;
import org.lwjgl.util.yoga.Yoga;

/**
 * A single character
 */
public class BitmapCharacter extends StandardElement implements DrawableElement {
    
    String text;
    
    Vector3f color = new Vector3f(1.0f);

    Font font;
    
    
    /**
     * Constructor
     * @param font
     * @param posX
     * @param posY
     * @param width
     * @param height
     * @param toDraw
     */
    public BitmapCharacter(Font font, int width, int height, char toDraw){
        super();
        setWidth(width);
        setHeight(height);
        this.text = "" + toDraw;
        this.font = font;
    }

    /**
     * Creates a bitmap character that will be positioned by Yoga
     * @param font The font of the character
     * @param toDraw The glyph to draw
     */
    public BitmapCharacter(Font font, char toDraw){
        super();
        this.text = "" + toDraw;
        this.font = font;
        Vector3f discreteDims = this.font.getDimensionOfCharacterDiscrete(toDraw);
        setMinWidth((int)discreteDims.x);
        setMinHeight((int)discreteDims.y);
    }
    
    
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
    
    public void setColor(Vector3f color) {
        this.color = color;
    }

    
    
    @Override
    public void draw(
        RenderPipelineState renderPipelineState,
        OpenGLState openGLState,
        int parentFramebufferPointer,
        int parentPosX,
        int parentPosY,
        int parentWidth,
        int parentHeight
    ){
        Globals.renderingEngine.bindFramebuffer(parentFramebufferPointer);
        openGLState.glViewport(parentWidth, parentHeight);
        float ndcX =      (float)(getInternalX() + parentPosX)/parentWidth;
        float ndcY =      (float)(parentHeight - (getInternalY() + parentPosY))/parentHeight;
        float ndcWidth =  (float)getInternalWidth()/parentWidth;
        float ndcHeight = (float)getInternalHeight()/parentHeight;
//        float charWidth = ndcWidth/cols;
//        float charHeight = ndcHeight/rows;
        char toDraw = text.charAt(0);
        Vector3f characterPosition = new Vector3f(ndcX,ndcY,0);
        Vector3f characterDimensions = new Vector3f(ndcWidth,ndcHeight,0);
        Vector3f bitMapPosition = this.font.getPositionOfCharacter(toDraw);
        Vector3f bitMapDimension = this.font.getDimensionOfCharacter(toDraw);
//        bitMapDimension.y = 1;
//        System.out.println(bitMapPosition);
//        System.out.println(bitMapDimension);
//        System.out.println("\n\n");
        //load model and try overwriting with font material
        Model charModel = Globals.assetManager.fetchModel(AssetDataStrings.BITMAP_CHARACTER_MODEL);
        Material mat = this.font.getMaterial();
        charModel.tryOverwriteMaterial(mat);
        if(charModel != null && toDraw != ' '){
            charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "mPosition", characterPosition);
            charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "mDimension", characterDimensions);
            charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "tPosition", bitMapPosition);
            charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "tDimension", bitMapDimension);
            charModel.pushUniformToMesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME, "color", color);
            charModel.drawUI();
        }
    }
    
    public boolean visible = false;

    public boolean getVisible() {
        return visible;
    }

    public void setVisible(boolean draw) {
        this.visible = draw;
    }

    public boolean handleEvent(Event event){
        return true;
    }

    @Override
    public void applyYoga(int parentX, int parentY) {
        //get the values from yoga
        float leftRaw = Yoga.YGNodeLayoutGetLeft(yogaNode);
        float topRaw = Yoga.YGNodeLayoutGetTop(yogaNode);
        //apply the values to this component
        this.internalPositionX = (int)leftRaw;
        this.internalPositionY = (int)topRaw;
        this.internalWidth = (int)Yoga.YGNodeLayoutGetWidth(yogaNode);
        this.internalHeight = (int)Yoga.YGNodeLayoutGetHeight(yogaNode);
        //calculate absolute values
        if(!useAbsolutePosition){
            this.absoluteX = parentX + internalPositionX;
            this.absoluteY = parentY + internalPositionY;
        }
    }
    
}
