/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2018 Pelican Mapping
* MIT License
*/
#ifndef OSGEARTH_DRIVERS_MP_TERRAIN_ENGINE_TILE_NODE
#define OSGEARTH_DRIVERS_MP_TERRAIN_ENGINE_TILE_NODE 1

#include "Common"
#include "TileModel"
#include <osgEarth/TerrainTileNode>

namespace osgEarth { namespace Drivers { namespace MPTerrainEngine
{
    /**
     * Node that represents a single terrain tile that was compiled from
     * a TileModel (and corresponds to one TileKey). The matrixtransform
     * localizes the TileNode within the terrain.
     */
    class TileNode : public osg::MatrixTransform                     
    {
    public: // osgEarth::TerrainTileNode
        
        const TileKey& getKey() const { return _key; }

        osg::Texture* getElevationTexture() const;

        osg::RefMatrixf* getElevationTextureMatrix() const;

        osg::Texture* getNormalTexture() const;

        osg::RefMatrixf* getNormalTextureMatrix() const;


    public:
        /**
         * Constructs a new tile node
         */
        TileNode(const TileKey& key, TileModel* model, const osg::Matrixd& matrix);

        /**
         * True if this is a valid tile node.
         * Subclass may override (see InvalidTileNode)
         */
        virtual bool isValid() const { return true; }

        /**
         * Access the source data model that built this tile.
         */
        const TileModel* getTileModel() { return _model.get(); }

        /**
         * Sets the last traversal frame manually. A parent TileGroup
         * will call this to prevent the born-time from resetting 
         * when traversing the tile's children.
         */
        void setLastTraversalFrame(unsigned frame);

        /**
         * Tells the tile node the current map revision, which is turn
         * will determine whether the tile is dirty and needs updating.
         */
        void setMapRevision( const Revision& value ) { _maprevision = value; }

        /**
         * Flags this Tile as dirty, regardless of whether the revisions are in sync.
         */
        void setDirty() { _dirty = true; }

        /**
         * Whether the tile is dirty and was traversed (and if therefore ready for
         * a dynamic update)
         */
        bool isOutOfDate() const { return _outOfDate; }

        /**
         * The tile-aligned bounding box of the terrain geometry.
         */
        void setTerrainBoundingBox(const osg::BoundingBox& bbox) { _terrainBBox = bbox; }
        const osg::BoundingBox& getTerrainBoundingBox() const { return _terrainBBox; }

    public:

        // called by the TileNodeRegistry when a tilenode that this tile was waiting
        // on has arrived.
        void notifyOfArrival(TileNode* waitee);


    public: // TileNodeContainer

        TileNode* getTileNode() { return this; }    

    public: // OVERRIDES

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

        virtual void resizeGLObjectBuffers(unsigned maxSize);
        virtual void releaseGLObjects(osg::State* state) const;

    protected:

        virtual ~TileNode() { }

        TileKey                            _key;
        osg::ref_ptr<TileModel>            _model;
        unsigned                           _lastTraversalFrame;
        Revision                           _maprevision;
        bool                               _outOfDate;
        bool                               _dirty;
        osg::ref_ptr<osg::RefMatrixf>      _elevTexMat;
        osg::ref_ptr<osg::RefMatrixf>      _normalTexMat;
        osg::BoundingBox                   _terrainBBox;
    };


    typedef std::vector< osg::ref_ptr<TileNode> > TileNodeVector;


    /**
     * Marker class - the engine will return one of these when a TileNode
     * load fails permanently. It will also blacklist the TileKey.
     */
    class InvalidTileNode : public TileNode
    {
    public:
        InvalidTileNode(const TileKey& key) : TileNode(key, 0L, osg::Matrix()) { }
        bool isValid() const { return false; }
    protected:
        virtual ~InvalidTileNode() { }
    };


} } } // namespace osgEarth::Drivers::MPTerrainEngine

#endif // OSGEARTH_DRIVERS_MP_TERRAIN_ENGINE_TILE_NODE
