/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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 OSGPRODUCER_OSGCAMERAGROUP_H
#define OSGPRODUCER_OSGCAMERAGROUP_H 1


#include <Producer/CameraGroup>

#include <osg/Timer>
#include <osg/ArgumentParser>
#include <osg/ApplicationUsage>
#include <osg/Group>
#include <osg/StateSet>
#include <osg/FrameStamp>
#include <osg/DisplaySettings>
#include <osg/CullSettings>
#include <osg/Matrixd>

#include <osgProducer/OsgSceneHandler>

namespace osgProducer {

class OSGPRODUCER_EXPORT OsgCameraGroup : public Producer::CameraGroup
{
    public :

        OsgCameraGroup();

        OsgCameraGroup(Producer::CameraConfig *cfg);

        OsgCameraGroup(const std::string& configFile);

        OsgCameraGroup(osg::ArgumentParser& arguments);

        virtual ~OsgCameraGroup();


        void setApplicationUsage(osg::ApplicationUsage* au) { _applicationUsage = au; }
        
        osg::ApplicationUsage* getApplicationUsage() { return _applicationUsage; }
        
        const osg::ApplicationUsage* getApplicationUsage() const { return _applicationUsage; }


        typedef std::vector < Producer::ref_ptr<osgProducer::OsgSceneHandler> > SceneHandlerList;

        SceneHandlerList& getSceneHandlerList() { return _shvec;}

        const SceneHandlerList& getSceneHandlerList() const { return _shvec;}


        void setSceneData( osg::Node *scene );
        
        osg::Node *getSceneData() { return _scene_data.get(); }

        const osg::Node *getSceneData() const { return _scene_data.get(); }

        

        void setSceneDecorator( osg::Group* decorator);
        
        osg::Group* getSceneDecorator() { return _scene_decorator.get(); }

        const osg::Group* getSceneDecorator() const { return _scene_decorator.get(); }


        osg::Node* getTopMostSceneData();

        const osg::Node* getTopMostSceneData() const;


        /** update internal structures w.r.t updated scene data.*/        
        virtual void updatedSceneData();


        void setDisplaySettings( osg::DisplaySettings *ds ) { _ds = ds; }

        osg::DisplaySettings *getDisplaySettings() { return _ds.get(); }
        
        const osg::DisplaySettings *getDisplaySettings() const { return _ds.get(); }
        
        
        void setCullSettings( const osg::CullSettings& cs) { _cullSettings = cs; }
        
        osg::CullSettings& getCullSettings() { return _cullSettings; }
        
        const osg::CullSettings& getCullSettings() const { return _cullSettings; }
        
        
        
        void setFrameStamp( osg::FrameStamp* fs );

        osg::FrameStamp *getFrameStamp() { return _frameStamp.get(); }

        const osg::FrameStamp *getFrameStamp() const { return _frameStamp.get(); }


        void setGlobalStateSet( osg::StateSet *sset );

        osg::StateSet *getGlobalStateSet() { return _global_stateset.get(); }

        const osg::StateSet *getGlobalStateSet() const { return _global_stateset.get(); }


#ifdef USE_DEPRECATED_API
        void setBackgroundColor( const osg::Vec4& backgroundColor) { setClearColor(backgroundColor); }

        const osg::Vec4& getBackgroundColor() const { return getClearColor(); }
#endif

        void setClearColor( const osg::Vec4& clearColor );

        const osg::Vec4& getClearColor() const;


        void setLODScale( float scale );

        float getLODScale() const;

        void setFusionDistance( osgUtil::SceneView::FusionDistanceMode mode,float value=1.0f);


        /** Set the options to set up SceneView with, see osgUtil::SceneView::Options for available options.*/
        void setRealizeSceneViewOptions(unsigned int options) { _realizeSceneViewOptions = options; }

        unsigned int getRealizeSceneViewOptions() { return _realizeSceneViewOptions; }


        /** RealizeCallback class one should override to provide an the implemention of realize callbacks.
          * Note, this callback overrides the normal call to OsgSceneHandler::init() so it become the your
          * responisibility to call this within your callback if required, it is a safe assumption to
          * always call OsgSceneHandler::init() within your callback..*/
        class OSGPRODUCER_EXPORT RealizeCallback : public osg::Referenced
        {
        public:
            virtual void operator()( OsgCameraGroup& cg, OsgSceneHandler& sh, const Producer::RenderSurface & rs) = 0;
            
        protected:
            virtual ~RealizeCallback(); // {}
        };

        /** Set the realize callback to use when once the render surfaces are realized.*/
        void setRealizeCallback( RealizeCallback* cb) { _realizeCallback = cb; }

        /** Get the realize callback.*/
        RealizeCallback* getRealizeCallback() { return _realizeCallback.get(); }
        
        /** Get the const realize callback.*/
        const RealizeCallback* getRealizeCallback() const { return _realizeCallback.get(); }


        void advance();

        /** Set the threading model and then call realize().*/
        virtual bool realize(ThreadingModel thread_model );

        /** Realize the render surfaces (OpenGL graphics) and various threads, and call any realize callbacks.*/
        virtual bool realize();

        /** Set the model view matrix of the camera group,
          * by individually set all the camera groups's camera.*/
        virtual void setView(const osg::Matrixd& matrix);
        
        /** Get the model view martrix of the camera group,
          * taking its value for camera 0.*/
        osg::Matrixd getViewMatrix() const;


        virtual void sync();

        /** Dispatch the cull and draw for each of the Camera's for this frame.*/
        virtual void frame();
        
        

    protected :


        virtual void setUpSceneViewsWithData();


        osg::ApplicationUsage*                  _applicationUsage;

        osg::ref_ptr<osg::Node>                 _scene_data;
        osg::ref_ptr<osg::Group>                _scene_decorator;

        osg::ref_ptr<osg::StateSet>             _global_stateset;
        osg::Vec4                               _clear_color;
        
        osgUtil::SceneView::FusionDistanceMode  _fusionDistanceMode;
        float                                   _fusionDistanceValue;

        unsigned int                            _realizeSceneViewOptions;
        
        SceneHandlerList                        _shvec;
        
        osg::ref_ptr<RealizeCallback>           _realizeCallback;
        
        osg::ref_ptr<osg::DisplaySettings>      _ds;
        bool                                    _initialized;
        
        osg::CullSettings                       _cullSettings;

        unsigned int    _frameNumber;
        osg::Timer      _timer;
        osg::Timer_t    _start_tick;
        osg::ref_ptr<osg::FrameStamp>           _frameStamp;

        void _init();
};

}

#endif
