/* osgEarth
* Copyright 2008-2014 Pelican Mapping
* MIT License
*/
#ifndef OSGEARTH_DRIVERS_REX_TERRAIN_ENGINE_SELECTION_INFO
#define OSGEARTH_DRIVERS_REX_TERRAIN_ENGINE_SELECTION_INFO 1

#include "Common"
#include <osg/NodeVisitor>
#include <osgEarth/Profile>
#include <osgEarth/TileKey>
#include <vector>


namespace osgEarth { namespace REX
{
    /**
     * SelectionInfo is a data structure that holds the LOD distance switching 
     * information for the terrain, to support paging and LOD morphing. 
     * This is calculated once when the terrain is first created.
     */
    class SelectionInfo
    {
    public:
        struct LOD
        {
            double _visibilityRange;
            double _morphStart;
            double _morphEnd;
            unsigned _minValidTY, _maxValidTY;
        };

    public:
        SelectionInfo() : _firstLOD(0) { }

        //! Initialize the selection into LODs
        void initialize(unsigned firstLod, unsigned maxLod, const Profile* profile, double mtrf, bool restrictPolarSubdivision);

        //! Set a new MRTF and re-initialize
        void setMTRFMappingFunction(std::function<double(double mtrf, double range)> func);

        //! Number of LODs
        unsigned getNumLODs(void) const { return _lods.size(); }

        //! Visibility and morphing information for a specific LOD
        const LOD& getLOD(unsigned lod) const;

        //! Fetch the effective visibility range and morphing range for a key
        void get(const TileKey& key, float& out_range, float& out_startMorphRange, float& out_endMorphRange) const;

        //! Get just the visibility range for a TileKey.
        //! inlined for speed (SL measured)
        inline float getRange(const TileKey& key) const {
            const LOD& lod = _lods[key.getLOD()];
            if (key.getTileY() >= lod._minValidTY && key.getTileY() <= lod._maxValidTY)
            {
                return lod._visibilityRange;
            }
            return 0.0f;
        }

    private:
        std::vector<LOD> _lods;
        unsigned _firstLOD, _maxLOD;
        osg::ref_ptr<const Profile> _profile;
        double _mrtf = 7.0;
        bool _restrictPolarSubdivision = false;
        std::function<double(double, double)> _mapMTRF = [](double mtrf, double range) { return mtrf; };

        static const double _morphStartRatio;
    };

} } // namespace

#endif
