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

import gov.nasa.worldwind.*;

/**
 * @author tag
 * @version $Id: AbstractLayer.java 1735 2007-05-05 09:50:26Z tgaskins $
 */
public abstract class AbstractLayer extends WWObjectImpl implements Layer
{
    private boolean enabled = true;
    private boolean pickable = true;
    private double opacity = 1d;
    private double minActiveAltitude = Double.MIN_VALUE;
    private double maxActiveAltitude = Double.MAX_VALUE;

    public boolean isEnabled()
    {
        return this.enabled;
    }

    public boolean isPickEnabled()
    {
        return pickable;
    }

    public void setPickEnabled(boolean pickable)
    {
        this.pickable = pickable;
    }

    public void setEnabled(boolean enabled)
    {
        this.enabled = enabled;
    }

    public String getName()
    {
        return this.myName();
    }

    public void setName(String name)
    {
        this.setValue(AVKey.DISPLAY_NAME, name);
    }

    public String toString()
    {
        return this.myName();
    }

    private String myName()
    {
        String myName = null;
        Object name = this.getValue(AVKey.DISPLAY_NAME);
        if (null != name)
            myName = name.toString();
        if (null == myName)
            myName = this.toString();
        return myName;
    }

    public double getOpacity()
    {
        return opacity;
    }

    public void setOpacity(double opacity)
    {
        this.opacity = opacity;
    }

    public double getMinActiveAltitude()
    {
        return minActiveAltitude;
    }

    public void setMinActiveAltitude(double minActiveAltitude)
    {
        this.minActiveAltitude = minActiveAltitude;
    }

    public double getMaxActiveAltitude()
    {
        return maxActiveAltitude;
    }

    public void setMaxActiveAltitude(double maxActiveAltitude)
    {
        this.maxActiveAltitude = maxActiveAltitude;
    }

    /**
     * Indicates whether the layer is in the view. The method implemented here is a default indicating the layer is in
     * view. Subclasses able to determine their presence in the view should override this implementation.
     *
     * @param dc the current draw context
     * @return <code>true</code> if the layer is in the view, <code>false</code> otherwise.
     */
    public boolean isLayerInView(DrawContext dc)
    {
        if (dc == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        return true;
    }

    /**
     * Indicates whether the layer is active based on arbitrary criteria. The method implemented here is a default
     * indicating the layer is active if the current altitude is within the layer's min and max active altitudes.
     * Subclasses able to consider more criteria should override this implementation.
     * @param dc the current draw context
     * @return <code>true</code> if the layer is active, <code>false</code> otherwise.
     */
    public boolean isLayerActive(DrawContext dc)
    {
        if (dc == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getView())
        {
            String message = WorldWind.retrieveErrMsg("layers.AbstractLayer.NoViewSpecifiedInDrawingContext");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        double altitude = dc.getView().getAltitude();

        return altitude >= this.minActiveAltitude && altitude <= this.maxActiveAltitude;
    }

    /**
     * @param dc the current draw context
     * @throws IllegalArgumentException if <code>dc</code> is null, or <code>dc</code>'s <code>Globe</code> or
     *                                  <code>View</code> is null
     */
    public void render(DrawContext dc)
    {
        if (!this.enabled)
            return; // Don't check for arg errors if we're disabled

        if (null == dc)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getGlobe())
        {
            String message = WorldWind.retrieveErrMsg("layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getView())
        {
            String message = WorldWind.retrieveErrMsg("layers.AbstractLayer.NoViewSpecifiedInDrawingContext");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (!this.isLayerActive(dc))
            return;

        if (!this.isLayerInView(dc))
            return;

        this.doRender(dc);
    }

    public void pick(DrawContext dc, java.awt.Point point)
    {
        if (!this.enabled)
            return; // Don't check for arg errors if we're disabled

        if (null == dc)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getGlobe())
        {
            String message = WorldWind.retrieveErrMsg("layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (null == dc.getView())
        {
            String message = WorldWind.retrieveErrMsg("layers.AbstractLayer.NoViewSpecifiedInDrawingContext");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (!this.isLayerActive(dc))
            return;

        if (!this.isLayerInView(dc))
            return;

        this.doPick(dc, point);
    }

    protected void doPick(DrawContext dc, java.awt.Point point)
    {
        // any state that could change the color needs to be disabled, such as GL_TEXTURE, GL_LIGHTING or GL_FOG.
        // re-draw with unique colors
        // store the object info in the selectable objects table
        // read the color under the coursor
        // use the color code as a key to retrieve a selected object from the selectable objects table
        // create an instance of the PickedObject and add to the dc via the dc.addPickedObject() method
    }

    public void dispose() // override if disposal is a supported operation
    {
    }

    protected abstract void doRender(DrawContext dc);
}
