/*****************************************************************************
 *                     Yumetech, Inc Copyright (c) 2005
 *                               Java Source
 *
 * This source is licensed under the BSD-style License
 * Please read http://www.opensource.org/licenses/bsd-license.php for more
 * information or docs/BSD.txt in the downloaded code.
 *
 * This software comes with the standard NO WARRANTY disclaimer for any
 * purpose. Use it at your own risk. If there's a problem you get to fix it.
 *
 ****************************************************************************/

package org.j3d.opengl.swt.internal.ri.windows;

// External imports
import javax.media.opengl.*;

import com.sun.opengl.impl.GLContextShareSet;
import com.sun.opengl.impl.windows.WGL;
import com.sun.opengl.impl.windows.WindowsGLContext;
import com.sun.opengl.impl.windows.WindowsGLDrawable;

// Local imports
import org.j3d.opengl.swt.internal.ri.SurfaceController;

/**
 * Representation of context management for onscreen surfaces
 *
 * @author Justin Couch
 * @version $Revision: 1.4 $
 */
class WindowsOnscreenGLContext extends WindowsGLContext
{
    private static final String NO_DELETE_ERR =
        "Unable to delete old GL context after surface changed";

    /** Handler for dealing with surface locking */
    private SurfaceController lockHandler;

    /** If an internal shutdown is pending this is set */
    private boolean shutdownPending;

    /**
     * Create a new instance of the onscreen surface controller.
     */
    WindowsOnscreenGLContext(WindowsGLDrawable drawable,
                             SurfaceController locker,
                             GLContext shareWith)
    {
        super(drawable, shareWith);

        lockHandler = locker;
        shutdownPending = false;
    }

    //---------------------------------------------------------------
    // Methods defined by GLContextImpl
    //---------------------------------------------------------------

    /**
     * Make the context current now.
     */
    protected int makeCurrentImpl() throws GLException
    {
        if(shutdownPending)
        {
            processShutdown();
            return CONTEXT_NOT_CURRENT;
        }

        int ret_val = 0;

        try
        {
            int lockRes = lockHandler.lockSurface();

            switch(lockRes)
            {
                case SurfaceController.SURFACE_NOT_READY:
                    ret_val = CONTEXT_NOT_CURRENT;
                    break;

                case SurfaceController.SURFACE_CHANGED:
                    if(shutdownPending)
                    {
                        processShutdown();
                        return CONTEXT_NOT_CURRENT;
                    }

                    if(hglrc != 0)
                    {
                        if(!WGL.wglDeleteContext(hglrc))
                            throw new GLException(NO_DELETE_ERR);

                        GLContextShareSet.contextDestroyed(this);

                        hglrc = 0;
                    }
                    ret_val = CONTEXT_CURRENT_NEW;
// This seems what should be here, but it doesn't seem to need it.
//                    ret_val = super.makeCurrentImpl();
                    break;

                default:
                    ret_val = super.makeCurrentImpl();
            }
        }
        catch(RuntimeException re)
        {
            try
            {
                // This may also toss an exception due to something that
                // messed up in the above code, so catch and ignore here.
                lockHandler.unlockSurface();
            }
            catch(RuntimeException re2)
            {
            }
        }

        if(shutdownPending)
        {
            processShutdown();
            return CONTEXT_NOT_CURRENT;
        }
        return ret_val;
    }

    /**
     * Release the underlying context implementation.
     */
    protected void releaseImpl() throws GLException
    {
        try
        {
            super.releaseImpl();
        }
        catch(GLException gle)
        {
        }

        if(lockHandler.isLockedSurface())
            lockHandler.unlockSurface();

        // So this one inline because the normal processShutdown() method
        // calls this method directly, resulting in a recursive loop.
        if(shutdownPending)
        {
            destroyImpl();
            shutdownPending = false;
        }
    }

    //---------------------------------------------------------------
    // Local Methods
    //---------------------------------------------------------------

    /**
     * Close down the context uncerimoniously now. Makes the context non-current, then
     * releases all the resources.
     */
    void shutdown()
    {
        if(hglrc == 0)
            return;

        if(!lockHandler.isLockedSurface())
            processShutdown();
        else
            shutdownPending = true;
    }

    private void processShutdown()
    {
        if(lockHandler.isLockedSurface())
            lockHandler.unlockSurface();

        setCurrent(null);
        releaseImpl();
        destroyImpl();
        shutdownPending = false;
    }
}
