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

#include <osg/Timer>
#include <osgUtil/SceneView>

#include <Producer/Camera>

#include <osgProducer/Export>



namespace osgProducer {

class OSGPRODUCER_EXPORT OsgSceneHandler : public Producer::Camera::SceneHandler
{
    public :
    
        OsgSceneHandler(osg::DisplaySettings *ds = NULL);
        
        /// set the scene view to which will manage rendering of the OSG scene.
        void setSceneView(osgUtil::SceneView* sceneView) { _sceneView = sceneView; }
        
        /// get the scene view.
        osgUtil::SceneView* getSceneView() { return _sceneView.get(); }
        
        /// get the const scene view.
        const osgUtil::SceneView* getSceneView() const { return _sceneView.get(); }

        /// override the init method to force it be run one at a time.
        virtual void init();
        
        
        class Callback : public osg::Referenced
        {
        public:
               virtual ~Callback() {}
               virtual void operator()(OsgSceneHandler&, Producer::Camera &) = 0;             
        };
        
        virtual void clear(Producer::Camera& camera)
        {
            if (_clearCallback.valid()) (*_clearCallback)(*this,camera);
            else clearImplementation(camera);
        }

        virtual void clearImplementation(Producer::Camera& camera);

        void setClearCallback(Callback* callback) { _clearCallback = callback; }
        Callback* getClearCallback() { return _clearCallback.get(); }
        const Callback* getClearCallback() const { return _clearCallback.get(); }


        virtual void cull(Producer::Camera& camera)
        {
            if (_cullCallback.valid()) (*_cullCallback)(*this,camera);
            else cullImplementation(camera);
        }

        virtual void cullImplementation(Producer::Camera& camera);

        void setCullCallback(Callback* callback) { _cullCallback = callback; }
        Callback* getCullCallback() { return _cullCallback.get(); }
        const Callback* getCullCallback() const { return _cullCallback.get(); }


        virtual void draw(Producer::Camera& camera)
        {
            if (_flushOfAllDeletedGLObjectsOnNextFrame && _sceneView.valid()) 
            {
                _sceneView->flushAllDeletedGLObjects();
            }
        
            if (_drawCallback.valid()) (*_drawCallback)(*this,camera);
            else drawImplementation(camera);
            
            _flushOfAllDeletedGLObjectsOnNextFrame = false;
        }
        
        virtual void drawImplementation(Producer::Camera& camera);

        void setDrawCallback(Callback* callback) { _drawCallback = callback; }
        Callback* getDrawCallback() { return _drawCallback.get(); }
        const Callback* getDrawCallback() const { return _drawCallback.get(); }

        void setContextID( int id );

        void setFlushOfAllDeletedGLObjectsOnNextFrame(bool flag) { _flushOfAllDeletedGLObjectsOnNextFrame = flag; }
        
        bool getFlushOfAllDeletedGLObjectsOnNextFrame() const { return _flushOfAllDeletedGLObjectsOnNextFrame; }

    protected:
    
        virtual ~OsgSceneHandler() {}
        
        
        osg::ref_ptr<osgUtil::SceneView> _sceneView;
    
        osg::ref_ptr<Callback> _clearCallback;
        osg::ref_ptr<Callback> _cullCallback;
        osg::ref_ptr<Callback> _drawCallback;
        
        osg::Timer_t           _frameStartTick;
        osg::Timer_t           _previousFrameStartTick;
        
        bool                   _flushOfAllDeletedGLObjectsOnNextFrame;
};

}

#endif
