/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSGTerrain
#define OSGTerrain 1

#include <osg/Group>
#include <osg/CoordinateSystemNode>

#include <osgTerrain/TerrainTile>

namespace osgTerrain {

/** Terrain provides a framework for loosely coupling height field data with height rendering algorithms.
  * This allows TerrainTechnique's to be plugged in at runtime.*/
class OSGTERRAIN_EXPORT Terrain : public osg::Group
{
    public:

        Terrain();
        
        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
        Terrain(const Terrain&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);

        META_Node(osgTerrain, Terrain);

        virtual void traverse(osg::NodeVisitor& nv);
        
        /** Set the sample ratio hint that TerrainTile should use when building geometry.
          * Defaults to 1.0, which means use all original sample points.*/
        void setSampleRatio(float ratio) 
        { 
            _sampleRatio  = ratio;
            dirtyRegisteredTiles();
        }

        /** Get the sample ratio hint.*/
        float getSampleRatio() const { return _sampleRatio; }


        /** Set the vertical scale hint.*/
        void setVerticalScale(float scale) 
        { 
            _verticalScale = scale;
            dirtyRegisteredTiles();
        }
    
        /** Get the vertical scale hint.*/
        float getVerticalScale() const { return _verticalScale; }
        
        /** Get the TerrainTile for a given TileID.*/
        TerrainTile* getTile(const TileID& tileID);

        /** Get the const TerrainTile for a given TileID.*/
        const TerrainTile* getTile(const TileID& tileID) const;
        
        /** Set the TerrainTechnique prototype from which TerrainTiles can clone the techniques from.*/
        void setTerrainTechniquePrototype(TerrainTechnique* technique) { _terrainTechnique = technique; }

        /** Get the TerrainTechnique prototype */
        TerrainTechnique* getTerrainTechniquePrototype() { return _terrainTechnique.get(); }
        
        /** Get the const TerrainTechnique protype*/
        const TerrainTechnique* getTerrainTechniquePrototype() const { return _terrainTechnique.get(); }

    protected:

        virtual ~Terrain();
        
        friend class TerrainTile;
        
        void dirtyRegisteredTiles();

        void registerTerrainTile(TerrainTile* tile);
        void unregisterTerrainTile(TerrainTile* tile);

        typedef std::map< TileID, TerrainTile* >    TerrainTileMap;
        typedef std::set< TerrainTile* >            TerrainTileSet;

        float                               _sampleRatio;
        float                               _verticalScale;

        mutable OpenThreads::Mutex          _mutex;
        TerrainTileSet                      _terrainTileSet;
        TerrainTileMap                      _terrainTileMap;

        osg::ref_ptr<TerrainTechnique>      _terrainTechnique;
};

}

#endif
