/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2008-2010 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTHUTIL_OCEANSURFACENODE
#define OSGEARTHUTIL_OCEANSURFACENODE

#include <osgEarthUtil/Common>
#include <osgEarth/ImageLayer>
#include <osg/Group>
#include <osg/observer_ptr>
#include <osg/CoordinateSystemNode>
#include <osg/Program>
#include <osg/Texture3D>

namespace osgEarth { namespace Util 
{
    using namespace osgEarth;

    /**
     * OceanSurfaceNode is a decorator node that animates the surface of the globe to simulate simple waves.
     * Note:  This only works with multitextured maps, not multipass.
     */
    class OSGEARTHUTIL_EXPORT OceanSurfaceNode : public osg::Group
    {
    public:
        /**
         * Creates a new OceanSurfaceNode
         */
        OceanSurfaceNode();

        /**
         * Sets the image layer to use as an ocean mask.
         */
        void setOceanMaskImageLayer( const ImageLayer* layer );

        /**
         * Gets the image layer being used as an ocean mask.
         */
        const ImageLayer* getOceanMaskImageLayer() const { return _maskLayer.get(); }

        /**
         *Gets the wave height
         */
        float getWaveHeight() const;

        /**
         *Sets the wave height
         */
        void setWaveHeight(float waveHeight);

        /**
         *Gets the range at which the effect starts to show.
         */
        float getMaxRange() const;

        /**
         *Sets the max range at which the effect starts to show
         */
        void setMaxRange(float maxRange);

        /**
         *Gets the period of the wave
         */
        float getPeriod() const;

        /**
         *Sets the period of the wave
         */
        void setPeriod(float period);

        /**
         *Gets whether the ocean effect is enabled
         */
        bool getEnabled() const;

        /**
         *Sets whether the ocean effect is enabled
         */
        void setEnabled(bool enabled);

        /**
         *Gets whether to invert the mask ocean mask.
         */
        bool getInvertMask() const;
        
        /**
         *Sets whether to invert the mask ocean mask.
         *Normally, transparant areas are considered ocean.  When inverted, transparent areas are considered land.
         */
        void setInvertMask(bool invertMask);

        /**
         * Sets an optional ocean color. The ocean will take on this color based on the 
         * alpha values in the masking texture.
         */
        void setModulationColor( const osg::Vec4f& color );

        osg::Vec4f getModulationColor() const;

        /**
         * Gets the period of the ocean animation effect in seconds
         */
        float getOceanAnimationPeriod() const;

        /**
         * Sets the period of the ocean animation effect in seconds
         */
        void setOceanAnimationPeriod(float oceanAnimationPeriod);

        /**
         *Gets the ocean surface image to the given 3D image.
         */
        osg::Image* getOceanSurfaceImage() const;
        
        /**
         *Sets the ocean surface image to the given 3D image.
         */
        void setOceanSurfaceImage( osg::Image* image);

        /**
         *Gets the size of the ocean surface image in radians
         */
        float getOceanSurfaceImageSizeRadians() const;

        /**
         *Sets the size of the ocean surface image in radians
         */
        void setOceanSurfaceImageSizeRadians( float size );

		/**
		 *Sets whether or not to adjust the height of the ocean to always be at MSL 0 and ignore the current vert height
		 */
		void setAdjustToMSL( bool adjustToMSL);
		
		/**
		 *Gets whether or not to adjust the height of the ocean to always be at MSL 0 and ignore the current vert height
		 */
		bool getAdjustToMSL() const;

    public:
        virtual void traverse( osg::NodeVisitor& nv );

    private:
        void rebuildShaders();

        void shadersDirty(bool value);
        bool _shadersDirty;

        float _maxRange;
        UID _oceanMaskLayerUID;
        int _oceanSurfaceTextureUnit;
        bool _oceanSurfaceTextureApplied;
        float _waveHeight;
        float _period;
        bool _enabled;
        bool _invertMask;
		bool _adjustToMSL;
        osg::observer_ptr<osg::CoordinateSystemNode> _csn;
        optional<osg::Vec4f> _oceanColor;
        float _oceanAnimationPeriod;
        float _oceanSurfaceImageSizeRadians;
        osg::ref_ptr< osg::Image > _oceanSurfaceImage;
        osg::ref_ptr< osg::Texture3D > _oceanSurfaceTexture;
        osg::observer_ptr< const ImageLayer > _maskLayer;
    };

} } // namespace osgEarth::Util

#endif //OSGEARTHUTIL_OCEANSURFACENODE
