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

#include <osgEarth/TerrainEngineNode>
#include <osgEarth/TextureCompositor>
#include <osgEarth/Map>
#include <osgEarth/Revisioning>
#include <osgEarth/TaskService>

#include "OSGTerrainOptions"
#include "OSGTileFactory"
#include "KeyNodeFactory"
#include "TileBuilder"

#include <osg/Geode>
#include <osg/NodeCallback>

using namespace osgEarth;

class OSGTerrainEngineNode : public TerrainEngineNode
{
public:
    OSGTerrainEngineNode();
    OSGTerrainEngineNode( const OSGTerrainEngineNode& rhs, const osg::CopyOp& op =osg::CopyOp::DEEP_COPY_ALL );
    META_Node(osgEarth,OSGTerrainEngineNode);
    ~OSGTerrainEngineNode();

public:
    osg::Node* createNode(const TileKey& key);

public: // TerrainEngineNode overrides    
    virtual void preInitialize( const Map* map, const TerrainOptions& options );
    virtual void postInitialize( const Map* map, const TerrainOptions& options );
    virtual void validateTerrainOptions( TerrainOptions& options );
    virtual const TerrainOptions& getTerrainOptions() const { return _terrainOptions; }
    virtual void traverse( osg::NodeVisitor& );
    virtual osg::BoundingSphere computeBound() const;

public: // MapCallback adapter functions
    void onMapInfoEstablished( const MapInfo& mapInfo ); // not virtual!
    void onMapModelChanged( const MapModelChange& change ); // not virtual!

    UID getUID() const;
    OSGTileFactory* getTileFactory() const { return _tileFactory.get(); }
    class Terrain* getTerrain() const { return _terrain; }

public: // statics    
    static void registerEngine( OSGTerrainEngineNode* engineNode );
    static void unregisterEngine( UID uid );
    static void getEngineByUID( UID uid, osg::ref_ptr<OSGTerrainEngineNode>& output );

private:
    void init();
    void syncMapModel();

    void addImageLayer( ImageLayer* layer );
    void addElevationLayer( ElevationLayer* layer );

    void removeImageLayer( ImageLayer* layerRemoved );
    void removeElevationLayer( ElevationLayer* layerRemoved );

    void moveImageLayer( unsigned int oldIndex, unsigned int newIndex );
    void moveElevationLayer( unsigned int oldIndex, unsigned int newIndex );
    
    void updateElevation( Tile* tile );
    void installShaders();
    void updateTextureCombining();

private:
    osg::ref_ptr<OSGTileFactory>         _tileFactory;
    //class CustomTerrain* _terrain;
    class Terrain*               _terrain;
    UID                                  _uid;
    osgEarth::Drivers::OSGTerrainOptions _terrainOptions;
    Revision                             _shaderLibRev;
    osg::ref_ptr<TaskServiceManager>     _taskServiceMgr;

    // store a separate map frame for each of the traversal threads
    MapFrame* _update_mapf; // map frame for the main/update traversal thread
    MapFrame* _cull_mapf;   // map frame for the cull traversal thread

    osg::ref_ptr<TaskService>    _tileService;
    osg::ref_ptr<KeyNodeFactory> _keyNodeFactory;
    osg::ref_ptr<TileBuilder>    _tileBuilder;

    osg::Timer _timer;
    unsigned   _tileCount;
    double     _tileCreationTime;
    bool       _isStreaming;
};

#endif // OSGEARTH_ENGINE_OSGTERRAIN_ENGINE_NODE_H
