/*****************************************************************************
 *                     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.x11;

// External imports
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
import javax.media.opengl.GLException;

import com.sun.opengl.impl.GLDrawableImpl;
import com.sun.opengl.impl.x11.GLX;
import com.sun.opengl.impl.x11.XVisualInfo;
import org.eclipse.swt.internal.gtk.OS;

public abstract class X11GLDrawable extends GLDrawableImpl
{
    private static final String SHOULD_NOT_CALL_MSG =
        "Should not call this (should only be called for onscreen GLDrawables)";

    protected boolean isDoubleBuffered;

    protected long display;
    protected long drawable;
    protected long visualID;
    protected GLCapabilities capabilities;
    protected GLCapabilitiesChooser chooser;

    public X11GLDrawable(GLCapabilities capabilities,
                         GLCapabilitiesChooser chooser)
    {
        this.capabilities = (capabilities == null) ? null :
                            ((GLCapabilities) capabilities.clone());
        this.chooser = chooser;
        isDoubleBuffered = true;
    }

    //---------------------------------------------------------------------------
    // Methods defined by GLDrawable
    //---------------------------------------------------------------------------

    public void setRealized(boolean val)
    {
        throw new GLException(SHOULD_NOT_CALL_MSG);
    }

    public void destroy()
    {
        throw new GLException(SHOULD_NOT_CALL_MSG);
    }

    public void swapBuffers() throws GLException
    {
    }

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

    public long getDisplay()
    {
        return display;
    }

    public long getDrawable()
    {
        return drawable;
    }

    public boolean isDoubleBuffered()
    {
        return isDoubleBuffered;
    }

    protected XVisualInfo chooseVisual(boolean onscreen)
    {
        if(display == 0)
            throw new GLException("null display");

        // FIXME
        if(onscreen)
        {
            int x_screen = OS.XDefaultScreen((int)display);
                                                                                
            int[] glxAttrib =
                X11GLXUtils.glCapabilities2AttribList(capabilities,
                                                      false,
                                                      false,
                                                      display,
                                                      x_screen);
            XVisualInfo vinfo =
                GLX.glXChooseVisual(display, x_screen, glxAttrib, 0);

            if(vinfo == null)
                throw new GLException("Unable to locate matching XVisualInfo");

            return vinfo;
        }
        else
        {
            // It isn't clear to me whether we need this much code to handle
            // the offscreen case, where we're creating a pixmap into which
            // to render...this is what we (incorrectly) used to do for the
            // onscreen case

            int screen = 0; // FIXME: provide way to specify this?
            XVisualInfo vis = null;
            int[] count = new int[1];
            XVisualInfo template = XVisualInfo.create();
            template.screen(screen);
            XVisualInfo[] infos = null;
            GLCapabilities[] caps = null;

            infos = GLX.XGetVisualInfo(display, GLX.VisualScreenMask, template, count, 0);
            if(infos == null)
                throw new GLException("Error while enumerating available XVisualInfos");

            caps = new GLCapabilities[infos.length];
            for(int i = 0; i < infos.length; i++)
                caps[i] = X11GLXUtils.xvi2GLCapabilities(display, infos[i]);


            int chosen = chooser.chooseCapabilities(capabilities, caps, -1);
            if(chosen < 0 || chosen >= caps.length)
                throw new GLException("GLCapabilitiesChooser specified invalid index (expected 0.." + (caps.length - 1) + ")");

            vis = infos[chosen];
            if(vis == null)
                throw new GLException("GLCapabilitiesChooser chose an invalid visual");

            // FIXME: the storage for the infos array is leaked (should
            // clean it up somehow when we're done with the visual we're
            // returning)

            return vis;
        }
    }
}
