/* -*-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 OSGEARTH_TERRAIN_OPTIONS_H
#define OSGEARTH_TERRAIN_OPTIONS_H 1

#include <osgEarth/Common>
#include <osgEarth/Config>
#include <osgEarth/HeightFieldUtils>

namespace osgEarth
{
    /**
     * The LoadingPolicy configures how the terrain engine loads map data.
     */
    class OSGEARTH_EXPORT LoadingPolicy
    {
    public:
        /** Tile loading modes. */
        enum Mode {
            /** Load tiles using the standard OSG database pager mechanism. The default. */
            MODE_STANDARD,

            /** Load tiles using a task service thread pool, enforcing sequential display
                of tile LODs. */
            MODE_SEQUENTIAL,

            /** Load tiles using a task service thread pool, but prioritize loading of the
                highest visible LOD for imagery (elevation data is always sequential). */
            MODE_PREEMPTIVE
        };

    public:
        LoadingPolicy( const Config& conf =Config() );
        LoadingPolicy( const Mode& mode );

    public: // Configrable
        virtual Config getConfig() const;
        virtual void fromConfig( const Config& conf );

    public:
        /**
         * Gets or sets the tile loading mode.
         */
        optional<Mode>& mode() { return _mode; }
        const optional<Mode>& mode() const { return _mode; }

        /**
         * Gets or sets the number of loading threads to use per CPU core.
         *
         * In STANDARD mode, this affects the number of OSG database pager threads;
         * in SEQUENTIAL or PREEMPTIVE mode, this sets the number of task thread
         * pool threads.
         */
        optional<float>& numLoadingThreadsPerCore() { return _numLoadingThreadsPerCore; }
        const optional<float>& numLoadingThreadsPerCore() const { return _numLoadingThreadsPerCore; }

        /**
         * Gets or sets the total number of loading threads to use.
         *
         * In STANDARD mode, this affects the number of OSG database pager threads;
         * in SEQUENTIAL or PREEMPTIVE mode, this sets the number of task thread
         * pool threads.
         */
        const optional<int>& numLoadingThreads() const { return _numLoadingThreads; }
        optional<int>& numLoadingThreads() { return _numLoadingThreads; }

        /**
         * Gets or sets the number of threads to allocate for regenerating terrain
         * tiles in the background. This only applies in SEQUENTIAL or PREEMPTIVE
         * mode.
         */
        const optional<int>& numCompileThreads() const { return _numCompileThreads; }
        optional<int>& numCompileThreads() { return _numCompileThreads; }

        /**
         * Gets or sets the number of threads to allocate for regenerating terrain
         * tiles in the background. This only applies in SEQUENTIAL or PREEMPTIVE
         * mode.
         */
        const optional<float>& numCompileThreadsPerCore() const { return _numCompileThreadsPerCore; }
        optional<float>& numCompileThreadsPerCore() { return _numCompileThreadsPerCore; }

    protected:
        optional<Mode> _mode;
        optional<int>   _numLoadingThreads;
        optional<float> _numLoadingThreadsPerCore;
        optional<int>   _numCompileThreads;
        optional<float> _numCompileThreadsPerCore;
    };

    extern OSGEARTH_EXPORT int computeLoadingThreads(const LoadingPolicy& policy);
    
    /**
     * Base class for the configuration for a terrain engine driver.
     */
    class OSGEARTH_EXPORT TerrainOptions : public DriverConfigOptions
    {
    public:
        TerrainOptions( const ConfigOptions& options =ConfigOptions() );
       
        /**
         * Sets or gets the scale factor for height-field values.
         * Default = 1.0
         */
        optional<float>& verticalScale() { return _verticalScale; }
        const optional<float>& verticalScale() const { return _verticalScale; }

        /**
         * The sample ratio for height fields. I.e., the terrain engine
         * will sample heightfield grids at this ratio
         * Default = 1.0
         */
        optional<float>& heightFieldSampleRatio() { return _heightFieldSampleRatio; }
        const optional<float>& heightFieldSampleRatio() const { return _heightFieldSampleRatio; }

        /**
         * The minimum tile LOD range as a factor of the tile's radius.
         * Default = 6.0.
         */
        optional<float>& minTileRangeFactor() { return _minTileRangeFactor; }
        const optional<float>& minTileRangeFactor() const { return _minTileRangeFactor; }

        /**
         * Whether to monitor terrain tile boundaries and match up the vertices.
         * Default = false.
         */
        optional<bool>& normalizeEdges() { return _normalizeEdges; }
        const optional<bool>& normalizeEdges() const { return _normalizeEdges; }

        /**
         * Whether to apply the default layer combination logic using TexEnvCombine.
         * Set this to false if you want to assume all control of how layers are combined.
         * This only applies when the LayeringTechnique is MULTITEXTURE.
         * Default = true.
         */
        optional<bool>& combineLayers() { return _combineLayers; }
        const optional<bool>& combineLayers() const { return _combineLayers; }

        /**
         * Properties associated with the tile loading subsystem.
         */
        optional<LoadingPolicy>& loadingPolicy() { return _loadingPolicy; }
        const optional<LoadingPolicy>& loadingPolicy() const { return _loadingPolicy; }

        /**
         * The image-layer fading attenuation distance
         */
        optional<float>& attenuationDistance() { return _attenuationDistance; }
        const optional<float>& attentuationDistance() const { return _attenuationDistance; }

        /**
         * Level-of-detail blending
         */
        optional<bool>& lodBlending() { return _lodBlending; }
        const optional<bool>& lodBlending() const { return _lodBlending; }

        /**
         * Transition time, in seconds, for tile image fade-in when LOD blending is enabled
         */
        optional<float>& lodTransitionTime() { return _lodTransitionTimeSeconds; }
        const optional<float>& lodTransitionTime() const { return _lodTransitionTimeSeconds; }

        /**
         * Available techniques for compositing image layers at runtime.
         */
        enum CompositingTechnique
        {
            COMPOSITING_AUTO,
            COMPOSITING_TEXTURE_ARRAY,
            COMPOSITING_MULTITEXTURE_GPU,
            COMPOSITING_MULTITEXTURE_FFP,
            COMPOSITING_MULTIPASS
        };

        /**
         * The texture composition technique
         */
        optional<CompositingTechnique>& compositingTechnique() { return _compositingTech; }
        const optional<CompositingTechnique>& compositingTechnique() const { return _compositingTech; }

        /**
         * The maximum level of detail to which the terrain should subdivide.
         */
        optional<int>& maxLOD() { return _maxLOD; }
        const optional<int>& maxLOD() const { return _maxLOD; }

        /**
         * Whether to explicity enable or disable GL lighting on the map node.
         */
        optional<bool>& enableLighting() { return _enableLighting; }
        const optional<bool>& enableLighting() const { return _enableLighting; }  
    
        /**
         * The interpolation method to use when sampling heightfields.
         */
        optional<ElevationInterpolation>& elevationInterpolation(void) { return _elevationInterpolation; }
        optional<ElevationInterpolation> const& elevationInterpolation(void) const { return _elevationInterpolation;}

   
    public:
        virtual Config getConfig() const;

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

    private:
        void fromConfig( const Config& conf );
            
        optional<float> _verticalScale;
        optional<float> _heightFieldSampleRatio;
        optional<float> _minTileRangeFactor;
        optional<bool> _normalizeEdges;
        optional<bool> _combineLayers;
        optional<LoadingPolicy> _loadingPolicy;
        optional<CompositingTechnique> _compositingTech;
        optional<int> _maxLOD;
        optional<bool> _enableLighting;
        optional<float> _attenuationDistance;
        optional<bool> _lodBlending;
        optional<float> _lodTransitionTimeSeconds;
#if 0
        optional<osg::Texture::FilterMode> _contourMagFilter;
        optional<osg::Texture::FilterMode> _contourMinFilter;
#endif
        optional<ElevationInterpolation> _elevationInterpolation;
    };
}

#endif // OSGEARTH_MAP_ENGINE_PROPERTIES_H
