package io.agora.api.example.examples.advanced.videoRender;

import android.graphics.Matrix;
import android.opengl.GLES20;

import io.agora.base.JavaI420Buffer;
import io.agora.base.internal.video.GlRectDrawer;
import io.agora.base.internal.video.GlUtil;
import io.agora.base.internal.video.RendererCommon;

public class YuvFboProgram {

    private int[] mFboTextureId;
    private final YuvUploader yuvUploader;
    private final GlRectDrawer glRectDrawer;

    private int mWidth, mHeight;
    private volatile boolean isRelease;

    // GL Thread
    public YuvFboProgram() {
        yuvUploader = new YuvUploader();
        glRectDrawer = new GlRectDrawer();
    }

    // GL Thread
    public void release() {
        isRelease = true;
        if (mFboTextureId != null) {
            GLES20.glDeleteFramebuffers(1, mFboTextureId, 0);
            GLES20.glDeleteTextures(1, mFboTextureId, 1);
            yuvUploader.release();
            glRectDrawer.release();
            mFboTextureId = null;
        }
    }

    // GL Thread
    public Integer drawYuv(byte[] yuv, int width, int height) {
        if (isRelease) {
            return -1;
        }
        if (mFboTextureId == null) {
            mFboTextureId = new int[2];
            GLES20.glGenFramebuffers(1, mFboTextureId, 0);
            int fboId = mFboTextureId[0];

            int texture = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
            mFboTextureId[1] = texture;

            mWidth = width;
            mHeight = height;
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
                    GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
                    GLES20.GL_COLOR_ATTACHMENT0,
                    GLES20.GL_TEXTURE_2D, texture, 0);
        } else if (mWidth != width || mHeight != height) {
            GLES20.glDeleteFramebuffers(1, mFboTextureId, 0);
            GLES20.glDeleteTextures(1, mFboTextureId, 1);
            mFboTextureId = null;
            return drawYuv(yuv, width, height);
        } else {
            int fboId = mFboTextureId[0];
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
        }
        GLES20.glViewport(0, 0, mWidth, mHeight);

        JavaI420Buffer i420Buffer = JavaI420Buffer.allocate(width, height);
        i420Buffer.getDataY().put(yuv, 0, i420Buffer.getDataY().limit());
        i420Buffer.getDataU().put(yuv, i420Buffer.getDataY().limit(), i420Buffer.getDataU().limit());
        i420Buffer.getDataV().put(yuv, i420Buffer.getDataY().limit() + i420Buffer.getDataU().limit(), i420Buffer.getDataV().limit());

        yuvUploader.uploadFromBuffer(i420Buffer);
        Matrix matrix = new Matrix();
        matrix.preTranslate(0.5f, 0.5f);
        matrix.preScale(1f, -1f);// I420-frames are upside down
        matrix.preTranslate(-0.5f, -0.5f);
        glRectDrawer.drawYuv(yuvUploader.getYuvTextures(), RendererCommon.convertMatrixFromAndroidGraphicsMatrix(matrix), width, height, 0, 0, width, height);

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        GLES20.glFlush();

        return mFboTextureId[1];
    }


}
