/*
Copyright (C) 2001, 2006 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.awt;

import gov.nasa.worldwind.*;

import javax.media.opengl.*;
import java.awt.*;

/**
 * <code>WorldWindowGLCanvas</code> is an AWT component for displaying World Wind {@link Model}s (globe and layers).
 * This implementation is a heavyweight AWT component. It derives from {@link GLCanvas} and therefore also provides a
 * general {@link GLDrawable} for OpenGL rendering.
 *
 * @author Tom Gaskins
 * @version $Id: WorldWindowGLCanvas.java 1793 2007-05-08 21:28:57Z tgaskins $
 */
public class WorldWindowGLCanvas extends GLCanvas implements WorldWindow
{
    private static final GLCapabilities caps = new GLCapabilities();

    static
    {
        caps.setAlphaBits(8);
        caps.setRedBits(8);
        caps.setGreenBits(8);
        caps.setBlueBits(8);
//        caps.setStencilBits(8);
        caps.setDepthBits(24);
    }

    private final WorldWindowGLAutoDrawable wwd; // everything delegates to wwd
    private InputHandler inputHandler;

    /**
     * Constructs a new <code>WorldWindowGLCanvas</code> window on the default graphics device.
     */
    public WorldWindowGLCanvas()
    {
        super(caps);
        try
        {
            this.wwd = new WorldWindowGLAutoDrawable(this); // TODO: Make class configurable
            this.createView();
            this.createDefaultInputHandler();
        }
        catch (Exception e)
        {
            String message = WorldWind.retrieveErrMsg("awt.WorldWindowGLSurface.UnabletoCreateWindow");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new WWRuntimeException(message, e);
        }
    }

    /**
     * Constructs a new <code>WorldWindowGLCanvas</code> window on the default graphics device that will share graphics
     * resources with another <code>WorldWindowGLCanvas</code> window. The other window, <code>sharewith</code>, may not
     * be null
     *
     * @param shareWith a <code>WorldWindowGLCanvas</code> with which to share graphics resources.
     * @throws NullPointerException if shareWith is null
     * @see GLCanvas#GLCanvas(GLCapabilities,GLCapabilitiesChooser,GLContext,GraphicsDevice)
     */
    public WorldWindowGLCanvas(WorldWindowGLCanvas shareWith)
    {
        super(caps, null, shareWith.getContext(), null);
        try
        {
            this.wwd = new WorldWindowGLAutoDrawable(this);
            this.createView();
            this.createDefaultInputHandler();
        }
        catch (Exception e)
        {
            String message = WorldWind.retrieveErrMsg("awt.WorldWindowGLSurface.UnabletoCreateWindow");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new WWRuntimeException(message, e);
        }
    }

    /**
     * Constructs a new <code>WorldWindowGLCanvas</code> window that will share graphics resources with another
     * <code>WorldWindowGLCanvas</code> window. The new window is created on the specified graphics device. Neither
     * <code> shareWith</code> or <code>device</code> may be null.
     *
     * @param shareWith a <code>WorldWindowGLCanvas</code> with which to share graphics resources.
     * @param device    the <code>GraphicsDevice</code> on which to create the window.
     * @throws NullPointerException     if <code>shareWith</code> is null
     * @throws IllegalArgumentException if <code>deevice</code> is null
     * @see GLCanvas#GLCanvas(GLCapabilities,GLCapabilitiesChooser,GLContext,GraphicsDevice)
     */
    public WorldWindowGLCanvas(WorldWindowGLCanvas shareWith, java.awt.GraphicsDevice device)
    {
        super(caps, null, shareWith.getContext(), device);

        if (device == null)
        {
            String msg = WorldWind.retrieveErrMsg("nullValue.DeviceIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, msg);
            throw new IllegalArgumentException(msg);
        }
        try
        {
            this.wwd = new WorldWindowGLAutoDrawable(this);
            this.createView();
            this.createDefaultInputHandler();
        }
        catch (Exception e)
        {
            String message = WorldWind.retrieveErrMsg("awt.WorldWindowGLSurface.UnabletoCreateWindow");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new WWRuntimeException(message, e);
        }
    }

    private void createView()
    {
        this.setView((View) WorldWind.createConfigurationComponent(
            gov.nasa.worldwind.AVKey.VIEW_CLASS_NAME));
    }

    private void createDefaultInputHandler()
    {
//        this.inputHandler = new gov.nasa.worldwind.awt.AWTInputHandler();
        this.inputHandler = (InputHandler) WorldWind.createConfigurationComponent(AVKey.INPUT_HANDLER_CLASS_NAME);
        this.inputHandler.setEventSource(this);
    }

    public InputHandler getInputHandler()
    {
        return inputHandler;
    }

    public void setInputHandler(InputHandler eventSource)
    {
        if (this.inputHandler != null)
            this.inputHandler.setEventSource(null); // remove this window as a source of events

        this.inputHandler = eventSource;
        if (this.inputHandler != null)
            this.inputHandler.setEventSource(this);
    }

    public SceneController getSceneController()
    {
        return this.wwd.getSceneController();
    }

    public PickedObjectList pick(java.awt.Point pickPoint)
    {
        return this.wwd.pick(pickPoint);
    }

    public void setModel(Model model)
    {
        // null models are permissible
        this.wwd.setModel(model);
    }

    public Model getModel()
    {
        return this.wwd.getModel();
    }

    public void setView(View view)
    {
        // null views are permissible
        if (view != null)
            this.wwd.setView(view);
    }

    public View getView()
    {
        return this.wwd.getView();
    }

    public void setModelAndView(Model model, View view)
    {   // null models/views are permissible
        this.setModel(model);
        this.setView(view);
    }

    public void addRenderingListener(RenderingListener listener)
    {
        this.wwd.addRenderingListener(listener);
    }

    public void removeRenderingListener(RenderingListener listener)
    {
        this.wwd.removeRenderingListener(listener);
    }

    public void addSelectListener(SelectListener listener)
    {
        this.inputHandler.addSelectListener(listener);
    }

    public void removeSelectListener(SelectListener listener)
    {
        this.inputHandler.removeSelectListener(listener);
    }

    public void addPositionListener(PositionListener listener)
    {
        this.inputHandler.addPositionListener(listener);
    }

    public void removePositionListener(PositionListener listener)
    {
        this.inputHandler.removePositionListener(listener);
    }
}
