package com.example.alfred.trogl;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.glDrawElements;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
import static android.opengl.GLES20.glVertexAttribPointer;
import static android.opengl.GLES20.glDisableVertexAttribArray;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.Matrix.multiplyMM;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.Matrix.scaleM;
import static android.opengl.Matrix.setIdentityM;
import static android.opengl.Matrix.translateM;

public class OGLTriangle {
    private static final int BYTES_PER_FLOAT = 4;
    private static final int POSITION_COMPONENT_COUNT = 2;
    private static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
    private static final int STRIDE = (POSITION_COMPONENT_COUNT + TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT;

    private FloatBuffer vertexData;
    private ByteBuffer indexArray;
    ShaderProgram program;
    private final float[] modelMatrix = new float[16];
    private float posX;
    private float posY;
    private float posZ;
    private float sizeX = 1.0f;
    private float sizeY = 1.0f;
    private float sizeZ = 1.0f;

    public float getSizeX() {
        return sizeX;
    }

    public void setSizeX(float sizeX) {
        this.sizeX = sizeX;
    }

    public float getSizeY() {
        return sizeY;
    }

    public void setSizeY(float sizeY) {
        this.sizeY = sizeY;
    }

    public float getSizeZ() {
        return sizeZ;
    }

    public void setSizeZ(float sizeZ) {
        this.sizeZ = sizeZ;
    }

    private OGLTriangle child = null;

    public OGLTriangle getChild() {
        return child;
    }

    public void setChild(OGLTriangle child) {
        this.child = child;
    }

    public float getPosX() {
        return posX;
    }

    public void setPosX(float posX) {
        this.posX = posX;
    }

    public float getPosY() {
        return posY;
    }

    public void setPosY(float posY) {
        this.posY = posY;
    }

    public float getPosZ() {
        return posZ;
    }

    public void setPosZ(float posZ) {
        this.posZ = posZ;
    }

    public OGLTriangle(String vertexShaderSource, String fragmentShaderSource) {
        float[] tableVerticesWithTriangles = {
                // x, y          s,t
                0, 0.2f,         0.5f,0,
                -0.2f,  0,       0,1,
                0.2f,  0,        1,1
        };

        vertexData = ByteBuffer
                .allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        vertexData.put(tableVerticesWithTriangles);

        byte[] tableIndices = {0, 1, 2};
        indexArray =  ByteBuffer.allocateDirect(3).put(tableIndices);

        program = new ShaderProgram(vertexShaderSource, fragmentShaderSource);
        program.compile();
        program.use();
    }

    public void draw(float[] projectionMatrix, float[] tMatrix, float[] sMatrix, float[] mMatrix) {
        vertexData.position(0);
        indexArray.position(0);

        float[] translateMatrix = new float[16];
        setIdentityM(translateMatrix, 0);
        float[] scaleMatrix = new float[16];
        setIdentityM(scaleMatrix, 0);

        program.use();
        if (mMatrix == null) {
            setIdentityM(modelMatrix, 0);
        } else {
            for (int i = 0; i < 16; i++)
                modelMatrix[i] = mMatrix[i];
        }

        translateM(translateMatrix, 0, posX, posY, posZ);
        scaleM(scaleMatrix, 0, sizeX, sizeY, sizeZ);

        float[] temp = new float[16];

        multiplyMM(temp, 0, modelMatrix, 0, translateMatrix, 0);
        for (int i = 0; i < 16; i++)
            modelMatrix[i] = temp[i];

        multiplyMM(temp, 0, modelMatrix, 0, scaleMatrix, 0);
        for (int i = 0; i < 16; i++)
            modelMatrix[i] = temp[i];

        float[] mvp = new float[16];
        multiplyMM(mvp, 0, projectionMatrix, 0, modelMatrix, 0);
        glUniformMatrix4fv(program.getMatrixLocation(), 1, false, mvp, 0);

        int aPositionLocation = program.getPositionLocation();
        glVertexAttribPointer(program.getPositionLocation(), POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glEnableVertexAttribArray(aPositionLocation);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indexArray);
        glDisableVertexAttribArray(aPositionLocation);

        if (child != null)
            child.draw(projectionMatrix, translateMatrix, scaleMatrix, modelMatrix);
    }
}
