package electrosphere.renderer.ui.elements;

import org.lwjgl.util.yoga.Yoga;

import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.events.Event;

/**
 * An implementation of element
 */
public class StandardElement implements Element {

    //these are set by the 
    public int width = -1;
    public int height = -1;
    
    public int parentWidth = 1;
    public int parentHeight = 1;

    int internalWidth;
    int internalHeight;
    int internalPositionX;
    int internalPositionY;
    int absoluteX;
    int absoluteY;
    boolean useAbsolutePosition = false;
    
    Element parent = null;

    public boolean visible = false;

    //the yoga node id
    long yogaNode = -1;

    /**
     * Constructor
     */
    protected StandardElement(){
        this.yogaNode = Yoga.YGNodeNew();
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public int getHeight() {
        return height;
    }

    @Override
    public int getRelativeX() {
        return internalPositionX;
    }

    @Override
    public int getRelativeY() {
        return internalPositionY;
    }

    @Override
    public int getAbsoluteX(){
        return absoluteX;
    }

    @Override
    public int getAbsoluteY(){
        return absoluteY;
    }

    public void setAbsolutePosition(boolean useAbsolutePosition){
        if(useAbsolutePosition){
            Yoga.YGNodeStyleSetPositionType(yogaNode, Yoga.YGPositionTypeAbsolute);
        } else {
            Yoga.YGNodeStyleSetPositionType(yogaNode, Yoga.YGPositionTypeRelative);
        }
        this.useAbsolutePosition = useAbsolutePosition;
    }

    @Override
    public void setWidth(int width) {
        this.internalWidth = width;
        this.width = width;
        Yoga.YGNodeStyleSetWidth(this.yogaNode, width);
    }

    @Override
    public void setHeight(int height) {
        this.internalHeight = height;
        this.height = height;
        Yoga.YGNodeStyleSetHeight(this.yogaNode, height);
    }

    @Override
    public void setPositionX(int posX) {
        this.internalPositionX = posX;
        this.absoluteX = posX;
    }

    @Override
    public void setPositionY(int posY) {
        this.internalPositionY = posY;
        this.absoluteY = posY;
    }

    @Override
    public void setParentWidth(int width) {
        this.parentWidth = width;
    }

    @Override
    public void setParentHeight(int height) {
        this.parentHeight = height;
    }

    public void setMarginTop(int marginTop){
        Yoga.YGNodeStyleSetMargin(this.yogaNode, Yoga.YGEdgeTop, marginTop);
    }

    public void setMarginRight(int marginRight){
        Yoga.YGNodeStyleSetMargin(this.yogaNode, Yoga.YGEdgeRight, marginRight);
    }

    public void setMarginBottom(int marginBottom){
        Yoga.YGNodeStyleSetMargin(this.yogaNode, Yoga.YGEdgeBottom, marginBottom);
    }

    public void setMarginLeft(int marginLeft){
        Yoga.YGNodeStyleSetMargin(this.yogaNode, Yoga.YGEdgeLeft, marginLeft);
    }

    public int getInternalX(){
        return internalPositionX;
    }

    public int getInternalY(){
        return internalPositionY;
    }

    public int getInternalWidth(){
        return internalWidth;
    }


    public int getInternalHeight(){
        return internalHeight;
    }

    public Element getParent(){
        return this.parent;
    }

    public void setParent(Element parent){
        this.parent = parent;
    }

    @Override
    public void destroy(){
        Yoga.YGNodeFree(this.yogaNode);
    }

    @Override
    public long getYogaNode() {
        return yogaNode;
    }

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





    @Override
    public boolean handleEvent(Event event) {
        boolean propagate = true;
        return propagate;
    }

    @Override
    public void setMaxWidth(int width) {
        Yoga.YGNodeStyleSetMaxWidth(yogaNode, width);
    }

    @Override
    public void setMaxWidthPercent(float percent) {
        Yoga.YGNodeStyleSetMaxWidthPercent(yogaNode, percent);
    }

    @Override
    public void setMaxHeight(int height) {
        Yoga.YGNodeStyleSetMaxHeight(yogaNode, height);
    }

    @Override
    public void setMaxHeightPercent(float percent) {
        Yoga.YGNodeStyleSetMaxHeight(yogaNode, percent);
    }

    @Override
    public void setMinWidth(int width) {
        Yoga.YGNodeStyleSetMinWidth(yogaNode, width);
    }

    @Override
    public void setMinWidthPercent(float percent) {
        Yoga.YGNodeStyleSetMinWidthPercent(yogaNode, percent);
    }

    @Override
    public void setMinHeight(int height) {
        Yoga.YGNodeStyleSetMinHeight(yogaNode, height);
    }

    @Override
    public void setMinHeightPercent(float percent) {
        Yoga.YGNodeStyleSetMinHeightPercent(yogaNode, percent);
    }

    /**
     * The value of the grow property
     * @param grow The grow value
     */
    public void setFlexGrow(float grow){
        Yoga.YGNodeStyleSetFlexGrow(yogaNode, grow);
    }

}
