import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.*;
import javax.media.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.*;
import javax.media.nativewindow.*;
import javax.swing.*;

public class SimpleTest implements GLEventListener {
    static GLProfile glp;
    static Frame     frame1=null,frame2=null;
    static GLCanvas  canvas1=null,canvas2=null;
    static boolean   fUseTwoFrames=true;
    
    static public class SimpleCanvas extends GLCanvas {
	public SimpleCanvas(GLCapabilities caps) {
	    super(caps);
	}
	
	public void display() {
	    super.display();
	}
    }
    
    public static void main(String[] args) {
	// NOTE:  this can NOT be on the AWT queue thread since AWT-EventQueue-0 -> SharedResourceRunner -> AWT-EventQueue-0
	System.err.println("#SimpleTest:  Calling: GLProfile.getDefault(), hasAWT="+GLProfile.isAWTAvailable());
        GLProfile glp = GLProfile.getDefault();
	System.err.println("#SimpleTest:  isAWT="+GLProfile.isAWTAvailable());
	
	try {
	    SwingUtilities.invokeAndWait(new Runnable() { public void run() { create_frame1(); } });
	} catch (Exception e) {
	    System.exit(0);
	}
	
	try {
	    if (fUseTwoFrames) SwingUtilities.invokeAndWait(new Runnable() { public void run() { create_frame2(); } });
	} catch (Exception e) {
	    System.exit(0);
	}
	
	try{
	    Thread.sleep(3000);
	} catch (Exception e) {
	}
	
	try {
	    //SwingUtilities.invokeAndWait(new Runnable() { public void run() { run_test(); } });
	} catch (Exception e) {
	}
	
	try {
	    if (fUseTwoFrames) SwingUtilities.invokeAndWait(new Runnable() { public void run() { close_frame2(true); } });
	} catch (Exception e) {
	    System.exit(0);
	}
	
	try {
	    SwingUtilities.invokeAndWait(new Runnable() { public void run() { close_frame1(true); } });
	} catch (Exception e) {
	    System.exit(0);
	}
	
	System.err.println("#SimpleTest:  glp.shutdown");
	glp.shutdown();
	System.err.println("#SimpleTest:  exiting");
	System.exit(0);
    }
    
    public static void create_frame1() {
	System.err.println("#SimpleTest:  Calling: new GLCapabilities(glp)");
        GLCapabilities caps = new GLCapabilities(glp);
	
	// create first frame
	System.err.println("#SimpleTest:  Calling: new Frame(\"Test A\")");
        frame1 = new Frame("Test A");
	System.err.println("#SimpleTest:  Calling: frame1.setSize(300, 300)");
        if (frame1 != null) frame1.setSize(300, 300);
	System.err.println("#SimpleTest:  Calling: canvas1 = new GLCanvas(caps)");
        canvas1 = new SimpleCanvas(caps);
	System.err.println("#SimpleTest:  Calling: canvas1.addGLEventListener(new SimpleTest())");
        canvas1.addGLEventListener(new SimpleTest());
	System.err.println("#SimpleTest:  Calling: frame1.add(canvas1)");
        frame1.add(canvas1);
	System.err.println("#SimpleTest:  Calling: frame1.setVisible(true)");
        frame1.setVisible(true);
    }
    
    public static void create_frame2() {
	System.err.println("#SimpleTest:  Calling: new GLCapabilities(glp)");
        GLCapabilities caps = new GLCapabilities(glp);
	
	// create second frame
	System.err.println("#SimpleTest:  Calling: new Frame(\"Test B\")");
        frame2 = new Frame("Test B");
	System.err.println("#SimpleTest:  Calling: frame2.setSize(300, 300)");
        frame2.setSize(300, 300);
	System.err.println("#SimpleTest:  Calling: canvas2 = new GLCanvas(caps)");
        canvas2 = new SimpleCanvas(caps);
	System.err.println("#SimpleTest:  Calling: canvas2.addGLEventListener(new SimpleTest())");
        canvas2.addGLEventListener(new SimpleTest());
	System.err.println("#SimpleTest:  Calling: frame2.add(canvas2)");
        frame2.add(canvas2);
	System.err.println("#SimpleTest:  Calling: frame2.setVisible(true)");
        frame2.setVisible(true);
    }
    
    public static void run_test() {
	// test first canvas
	if (canvas1 != null) swap_context1(canvas1);
    }
    
    public static void swap_context1(GLCanvas glCanvas) {
	// make sure this is the open gl thread
	if (Threading.isSingleThreaded() && !Threading.isOpenGLThread()) {
	    System.out.println("#SimpleTest::swap_context2:  not open gl thread.");
	    return;
	}
	
	// get context
	GLContext glContext = glCanvas.getContext();
	
	// swap context in and out
	GLContext glCurrent = GLContext.getCurrent();
	boolean fMadeCurrent = false;
	if (glCurrent != null && glCurrent != glContext) {
	    System.out.println("#SimpleTest::swap_context1:  glCurrent.release");
	      glCurrent.release();
	} else {
	    glCurrent = null;
	}
	if( glContext != null && glCurrent != glContext ) {
	    System.out.println("#SimpleTest::swap_context1:  glContext.makeCurrent");
	    glContext.makeCurrent();
	    fMadeCurrent = true;
	}
	if (fMadeCurrent) {
	    System.out.println("#SimpleTest::swap_context1:  glontext.release");
	    glContext.release();
	}
	if (glCurrent != null) {
	    System.out.println("#SimpleTest::swap_context1:  glCurrent.makeCurrent");
	    glContext.makeCurrent();
	}
    }
    
    public static void swap_context2(GLCanvas glCanvas,boolean fDraw) {
	// make sure this is the open gl thread
	if (Threading.isSingleThreaded() && !Threading.isOpenGLThread()) {
	    System.out.println("#SimpleTest::swap_context2:  not open gl thread.");
	    return;
	}
	
	// get context
	GLContext glContext = glCanvas.getContext();
	
	// check the current context and get the current context
	// NOTE: get context from gl so drawing routine is indenpendent of GLCanvas
	if (glContext == null)
	    return;
	GLContext glCurrent = GLContext.getCurrent();
	
	// set context
	boolean glCurrentReleased = false;
	boolean glContextCurrent  = false;
	try {
	    // check if context needs to be swapped
	    if (glCurrent != glContext) {
		// release the current context
		if (glCurrent != null) {
		    glCurrent.release();
		    glCurrentReleased = true;
		}
		
		// set the context
		if (glContext.makeCurrent() == GLContext.CONTEXT_NOT_CURRENT) {
		    System.out.println("#SimpleTest::swap_context2:  glContext could not be made current.");
		    return;
		}
		glContextCurrent = true;
		
		// draw
		if (fDraw) test_draw(glCanvas);
	    }
	} finally {
	    // check if context needs to be unswapped
	    if (glCurrent != glContext) {
		// release the context
		if (glContextCurrent)
		    glContext.release();
		
		// reset the old context
		if (glCurrent != null && glCurrentReleased)
		    glCurrent.makeCurrent();
	    }
	}
    }
    
    public static void test_draw(GLCanvas glCanvas) {
	GL2 gl = glCanvas.getGL().getGL2();
	gl.glClear(GL.GL_COLOR_BUFFER_BIT);
    }
    
    public static void close_frame1(boolean fDelay) {
	if (frame1 == null) return;
	
	System.err.println("#SimpleTest:  Calling: frame1.setVisible(false)");
        frame1.setVisible(false);
	System.err.println("#SimpleTest:  Calling: frame1.dispose()");
	frame1.dispose();
	
	try{
	    if (fDelay) Thread.sleep(1000);
	} catch (Exception e) {
	}
    }
    
    public static void close_frame2(boolean fDelay) {
	if (frame2 == null) return;
	
	System.err.println("#SimpleTest:  Calling: frame2.setVisible(false)");
        frame2.setVisible(false);
	System.err.println("#SimpleTest:  Calling: frame2.dispose()");
	frame2.dispose();
	
	try{
	    if (fDelay) Thread.sleep(1000);
	} catch (Exception e) {
	}
    }
    
    public void display(GLAutoDrawable drawable) {
	System.err.println("#SimpleTest:  Event Thread: "+Thread.currentThread()+" "+
			   Threading.isSingleThreaded()+" "+(Threading.isSingleThreaded() && Threading.isOpenGLThread()));
	drawable.getGL().getGL2().glClear(GL.GL_COLOR_BUFFER_BIT);
    }
    public void dispose(GLAutoDrawable drawable) { }
    public void init(GLAutoDrawable drawable) { }
    public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) { }
}
