/**
 * Copyright 2010 JogAmp Community. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of JogAmp Community.
 */
package com.jogamp.opengl.test.junit.jogl.glsl;

import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.glsl.ShaderState;

import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLDrawable;

import org.junit.Assert;

public class GLSLMiscHelper {
    public static final int frames_perftest = 600; // frames
    public static final int frames_warmup   = 100; // frames
    
    public static void validateGLArrayDataServerState(GL2ES2 gl, GLArrayDataServer data) {
        final ShaderState st = ShaderState.getShaderState(gl);
        int[] qi = new int[1];
        if(null != st) {            
            Assert.assertEquals(data, st.getAttribute(data.getName()));            
            if(st.shaderProgram().linked()) {
                Assert.assertEquals(data.getLocation(), st.getCachedAttribLocation(data.getName()));
                Assert.assertEquals(data.getLocation(), st.getAttribLocation(gl, data));
                Assert.assertEquals(data.getLocation(), st.getAttribLocation(gl, data.getName()));
                Assert.assertEquals(data.getLocation(), gl.glGetAttribLocation(st.shaderProgram().program(), data.getName()));                
            }
        }
        gl.glGetVertexAttribiv(data.getLocation(), GL2ES2.GL_VERTEX_ATTRIB_ARRAY_ENABLED, qi, 0);
        Assert.assertEquals(data.enabled()?GL.GL_TRUE:GL.GL_FALSE, qi[0]);
        gl.glGetVertexAttribiv(data.getLocation(), GL2ES2.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, qi, 0);
        Assert.assertEquals(data.getVBOName(), qi[0]);  
        Assert.assertEquals(data.getSizeInBytes(), gl.glGetBufferSize(data.getVBOName()));        
    }

    public static void pause(long ms) throws InterruptedException {
        long t0 = System.currentTimeMillis();
        while( System.currentTimeMillis() - t0 < ms) {
            Thread.sleep(ms);
        }        
    }
    
    public static void displayVCArrays(GLDrawable drawable, GL2ES2 gl, boolean preEnable, GLArrayDataServer vertices, GLArrayDataServer colors, boolean postDisable, int num, long postDelay) throws InterruptedException {
        System.err.println("screen #"+num);
        if(preEnable) {
            vertices.enableBuffer(gl, true);
            // invalid - Assert.assertEquals(vertices.getVBOName(), gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER));
            colors.enableBuffer(gl, true);
            // invalid - Assert.assertEquals(colors.getVBOName(), gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER));
            //
            // Above assertions are invalid, since GLSLArrayHandler will not bind the VBO to target
            // if the VBO is already bound to the attribute itself.
            // validateGLArrayDataServerState(..) does check proper VBO to attribute binding.
        }
        Assert.assertTrue(vertices.enabled());
        Assert.assertTrue(colors.enabled());
        
        validateGLArrayDataServerState(gl, vertices);
        validateGLArrayDataServerState(gl, colors);
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);        
        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
        if(postDisable) {
            vertices.enableBuffer(gl, false);
            colors.enableBuffer(gl, false);
            Assert.assertTrue(!vertices.enabled());
            Assert.assertTrue(!colors.enabled());
        }
        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
        drawable.swapBuffers();
        if(postDelay>0) { pause(postDelay); }        
    }
    
    public static void displayVCArraysNoChecks(GLDrawable drawable, GL2ES2 gl, boolean preEnable, GLArrayDataServer vertices, GLArrayDataServer colors, boolean postDisable) throws InterruptedException {
        if(preEnable) {
            vertices.enableBuffer(gl, true);
            colors.enableBuffer(gl, true);
        }
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);        
        if(postDisable) {
            vertices.enableBuffer(gl, false);
            colors.enableBuffer(gl, false);
        }
        drawable.swapBuffers();
    }
    
    public static GLArrayDataServer createRSVertices0(GL2ES2 gl, int location) {
        final ShaderState st = ShaderState.getShaderState(gl);
        
        // Allocate Vertex Array0
        GLArrayDataServer vertices0 = GLArrayDataServer.createGLSL("mgl_Vertex", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
        if(0<=location) {
            st.bindAttribLocation(gl, location, vertices0);
        }
        Assert.assertTrue(vertices0.isVBO());
        Assert.assertTrue(vertices0.isVertexAttribute());
        Assert.assertTrue(!vertices0.isVBOWritten());
        Assert.assertTrue(!vertices0.sealed());
        vertices0.putf(-2); vertices0.putf(2);  vertices0.putf(0);
        vertices0.putf(2);  vertices0.putf(2);  vertices0.putf(0);
        vertices0.putf(-2); vertices0.putf(-2); vertices0.putf(0);
        vertices0.putf(2);  vertices0.putf(-2); vertices0.putf(0);
        vertices0.seal(gl, true);
        Assert.assertTrue(vertices0.isVBOWritten());
        Assert.assertTrue(vertices0.sealed());
        Assert.assertEquals(4, vertices0.getElementCount());
        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());        
        Assert.assertEquals(vertices0.getVBOName(), gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER));
        validateGLArrayDataServerState(gl, vertices0);
        return vertices0;
    }
        
    public static GLArrayDataServer createRSVertices1(GL2ES2 gl) {            
        GLArrayDataServer vertices1 = GLArrayDataServer.createGLSL("mgl_Vertex", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); 
        Assert.assertTrue(vertices1.isVBO());
        Assert.assertTrue(vertices1.isVertexAttribute());
        Assert.assertTrue(!vertices1.isVBOWritten());
        Assert.assertTrue(!vertices1.sealed());
        vertices1.putf(-2); vertices1.putf(1);  vertices1.putf(0);
        vertices1.putf(2);  vertices1.putf(1);  vertices1.putf(0);
        vertices1.putf(-2); vertices1.putf(-1); vertices1.putf(0);
        vertices1.putf(2);  vertices1.putf(-1); vertices1.putf(0);
        vertices1.seal(gl, true);
        Assert.assertTrue(vertices1.isVBOWritten());
        Assert.assertTrue(vertices1.sealed());
        Assert.assertEquals(4, vertices1.getElementCount());
        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
        Assert.assertEquals(vertices1.getVBOName(), gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER));
        validateGLArrayDataServerState(gl, vertices1);
        return vertices1;
    }
        
    public static GLArrayDataServer createRSColors0(GL2ES2 gl, int location) {
        final ShaderState st = ShaderState.getShaderState(gl);
        GLArrayDataServer colors0 = GLArrayDataServer.createGLSL("mgl_Color", 4, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
        if(0<=location) {
            st.bindAttribLocation(gl, location, colors0);
        }        
        colors0.putf(1); colors0.putf(0); colors0.putf(0); colors0.putf(1);
        colors0.putf(0); colors0.putf(0); colors0.putf(1); colors0.putf(1);
        colors0.putf(1); colors0.putf(0); colors0.putf(0); colors0.putf(1);
        colors0.putf(1); colors0.putf(0); colors0.putf(0); colors0.putf(1);
        colors0.seal(gl, true);
        Assert.assertTrue(colors0.isVBO());
        Assert.assertTrue(colors0.isVertexAttribute());
        Assert.assertTrue(colors0.isVBOWritten());
        Assert.assertTrue(colors0.sealed());
        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
        Assert.assertEquals(colors0.getVBOName(), gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER));
        validateGLArrayDataServerState(gl, colors0);
        return colors0;
    }
    
    public static GLArrayDataServer createRSColors1(GL2ES2 gl) {        
        // Allocate Color Array1
        GLArrayDataServer colors1 = GLArrayDataServer.createGLSL("mgl_Color", 4, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
        colors1.putf(1); colors1.putf(0); colors1.putf(1); colors1.putf(1);
        colors1.putf(0); colors1.putf(1); colors1.putf(0); colors1.putf(1);
        colors1.putf(1); colors1.putf(0); colors1.putf(1); colors1.putf(1);
        colors1.putf(1); colors1.putf(0); colors1.putf(1); colors1.putf(1);
        colors1.seal(gl, true);
        Assert.assertTrue(colors1.isVBO());
        Assert.assertTrue(colors1.isVertexAttribute());
        Assert.assertTrue(colors1.isVBOWritten());
        Assert.assertTrue(colors1.sealed());
        Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError());
        Assert.assertEquals(colors1.getVBOName(), gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER));
        validateGLArrayDataServerState(gl, colors1);
        return colors1;        
    }    
}
