/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 * Copyright 2016 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 OSGEARTH_DRIVER_SIMPLE_OCEAN
#define OSGEARTH_DRIVER_SIMPLE_OCEAN 1

#include <osgEarthUtil/Ocean>
#include <osgEarth/MapNode>
#include <osgEarth/ImageLayer>
#include <osgEarth/URI>
#include <osgEarth/Registry>
#include <osgEarthSymbology/Color>

namespace osgEarth { namespace SimpleOcean
{
    using namespace osgEarth;
    using namespace osgEarth::Util;

    /**
     * Options for controlling the ocean surface node.
     * (header-only)
     */
    class SimpleOceanOptions : public OceanOptions
    {
    public:
        /** Nominal sea level in meters (relative to ellipsoid/geoid); default is zero. */
        optional<float>& seaLevel() { return _seaLevel; }
        const optional<float>& seaLevel() const { return _seaLevel; }

        /** Elevation offset (relative to seaLevel) at which ocean surface goes to min transparency.
         *  Not available when using a mask layer. */
        optional<float>& lowFeatherOffset() { return _lowFeatherOffset; }
        const optional<float>& lowFeatherOffset() const { return _lowFeatherOffset; }

        /** Elevation offset (relative to seaLevel) at which ocean surface goes to full transparency.
         *  Not available when using a mask layer. */
        optional<float>& highFeatherOffset() { return _highFeatherOffset; }
        const optional<float>& highFeatherOffset() const { return _highFeatherOffset; }

        /** Maximum LOD to subdivide ocean surface */
        optional<unsigned>& maxLOD() { return _maxLOD; }
        const optional<unsigned>& maxLOD() const { return _maxLOD; }

        /** Color of the ocean surface (before texturing) */
        optional<Color>& baseColor() { return _baseColor; }
        const optional<Color>& baseColor() const { return _baseColor; }

        /** Maximum visibile range of the ocean (at which is starts fading in) */
        optional<float>& maxRange() { return _maxRange; }
        const optional<float>& maxRange() const { return _maxRange; }

        /** Range over which ocean fades into view (starting at maxRange) */
        optional<float>& fadeRange() { return _fadeRange; }
        const optional<float>& fadeRange() const { return _fadeRange; }

        /** URI of the texture to blend and animate into the ocean surface. */
        optional<URI>& textureURI() { return _textureURI; }
        const optional<URI>& textureURI() const { return _textureURI; }

        /** Render bin number to assign to the ocean (in DepthSortedBin) */
        optional<int>& renderBinNumber() { return _renderBinNumber; }
        const optional<int>& renderBinNumber() const { return _renderBinNumber; }


        /** Image layer configuration for an optional "ocean mask" layer.
         *  This is an image layer that encodes areas of land versus ocean in the
         *  alpha channel of the image. The mapping is: [0...1] => [land...ocean] */
        optional<ImageLayerOptions>& maskLayer() { return _maskLayerOptions; }
        const optional<ImageLayerOptions>& maskLayer() const { return _maskLayerOptions; }

    public:
        SimpleOceanOptions( const ConfigOptions& conf =ConfigOptions() )
            : OceanOptions      ( conf ),
              _seaLevel         ( 0.0f ),
              _lowFeatherOffset ( -100.0f ),
              _highFeatherOffset( -10.0f ),
              _maxRange         ( 1000000.0f ),
              _fadeRange        ( 125000.0f ),
              _maxLOD           ( 20 ),
              _baseColor        ( Color("#1c6ba0ef") ),
              _renderBinNumber  ( 12 )
        {
            mergeConfig( _conf );
        }

        /** dtor */
        virtual ~SimpleOceanOptions() { }

    public:
        Config getConfig() const {
            Config conf = OceanOptions::getConfig();
            conf.set("sea_level",           _seaLevel );
            conf.set("high_feather_offset", _highFeatherOffset );
            conf.set("low_feather_offset",  _lowFeatherOffset );
            conf.set("max_range",           _maxRange );
            conf.set("fade_range",          _fadeRange );
            conf.set("max_lod",             _maxLOD );
            conf.set("base_color",          _baseColor );
            conf.set("texture_url",         _textureURI );
            conf.setObj("mask_layer",       _maskLayerOptions );
            conf.set("render_bin_number",   _renderBinNumber);
            return conf;
        }

    protected:
        void mergeConfig( const Config& conf ) {
            OceanOptions::mergeConfig( conf );
            fromConfig( conf );
        }

    private:
        void fromConfig( const Config& conf ) {
            conf.getIfSet("sea_level",           _seaLevel );
            conf.getIfSet("high_feather_offset", _highFeatherOffset );
            conf.getIfSet("low_feather_offset",  _lowFeatherOffset );
            conf.getIfSet("max_range",           _maxRange );
            conf.getIfSet("fade_range",          _fadeRange );
            conf.getIfSet("max_lod",             _maxLOD );
            conf.getIfSet("base_color",          _baseColor );
            conf.getIfSet("texture_url",         _textureURI );
            conf.getObjIfSet("mask_layer",       _maskLayerOptions );
            conf.getIfSet("render_bin_number",   _renderBinNumber);
        }

    private:
        optional<float>             _seaLevel;
        optional<float>             _lowFeatherOffset;
        optional<float>             _highFeatherOffset;
        optional<float>             _maxRange;
        optional<float>             _fadeRange;
        optional<unsigned>          _maxLOD;
        optional<Color>             _baseColor;
        optional<URI>               _textureURI;
        optional<ImageLayerOptions> _maskLayerOptions;
        optional<int>               _renderBinNumber;
    };

} } // namespace osgEarth::SimpleOcean

#endif // OSGEARTH_DRIVER_SIMPLE_OCEAN
