//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield
//Distributed under the terms of the GNU Library General Public License (LGPL)
//as published by the Free Software Foundation.

#ifndef OSGGLUT_VIEWER
#define OSGGLUT_VIEWER 1

#include <osg/Light>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/Timer>
#include <osg/DisplaySettings>

#include <osgUtil/GUIEventAdapter>
#include <osgUtil/CameraManipulator>
#include <osgUtil/SceneView>

#include <osgGLUT/Window>

#include <string>

namespace osgGLUT
{

/** A basic viewer base class which provides a window, simple keyboard and mouse interaction.
  * Please note, this viewer class has been developed via a rather haphazard
  * path and <i>needs</i> a total rewrite.  It currently suffices for osg demos
  * but shouldn't be viewed as the be all and end of osg viewer classes.
  * Someone please rewrite it :-)
  */
class OSGGLUT_EXPORT Viewer : public Window, public osgUtil::GUIActionAdapter
{
    public:

        Viewer();
        virtual ~Viewer();

        /** init is deprecated, you should use addViewport instead. init is
          * only available for backwards compatibility.*/
        virtual void init(osg::Node* rootnode);

        virtual void addViewport(osgUtil::SceneView* sv,
                                 float x     = 0.0, float y      = 0.0,        
                                 float width = 1.0, float height = 1.0);

        virtual void addViewport(osg::Node*,
                                 float x     = 0.0, float y      = 0.0,        
                                 float width = 1.0, float height = 1.0);

        const int getNumViewports() const { return _viewportList.size(); }

        osgUtil::SceneView* getViewportSceneView(unsigned int pos) 
            { return _viewportList[pos].sceneView.get(); }

        virtual bool open();
        virtual bool run();

        // called on each frame redraw..return the time in ms for each operation.
        virtual float app(unsigned int viewport); 
        virtual float cull(unsigned int viewport);
        virtual float draw(unsigned int viewport);

        // initialize the clock.
        long initClock();
        // time since initClock() in seconds.
        double clockSeconds() { return _timer.delta_s(_initialTick,clockTick()); }

        // update the number of ticks since the last frame update.
        osg::Timer_t updateFrameTick();
        
        // time from the current frame update and the previous one in seconds.
        double frameSeconds() { return _timer.delta_s(_lastFrameTick,_frameTick); }
        double frameRate() { return 1.0/frameSeconds(); }

        void help(std::ostream& fout);

        // handle multiple camera.
        unsigned int registerCameraManipulator(osgUtil::CameraManipulator* cm,
					       unsigned int viewport = 0);
        void selectCameraManipulator(unsigned int pos, 
				     unsigned int viewport = 0);

        // derived from osgUtil::GUIActionAdapter
        virtual void requestRedraw() {} // redraw always by idle callback done.
        virtual void requestContinuousUpdate(bool /*needed*/) {} // continuous update always
        virtual void requestWarpPointer(int x,int y);

        /** read the command line string list, removing any matched control sequences.*/
        void readCommandLine(std::vector<std::string>& commandLine);

    protected:

        virtual void display();
        virtual void reshape(GLint w, GLint h);
        virtual void mouseMotion(int x, int y);
        virtual void mousePassiveMotion(int x, int y);
        virtual void mouse(int button, int state, int x, int y);
        virtual void keyboard(unsigned char key, int x, int y);

        void setFocusedViewport(unsigned int pos);
        int mapWindowXYToSceneView(int x, int y);
        
        void showStats(const unsigned int i); // gwm 24.09.01 pass the viewport to collect sta for each viewport

        static Viewer*    s_theViewer;

        typedef std::vector<osg::ref_ptr<osgUtil::CameraManipulator> > CameraManipList;

        struct ViewportDef 
        {
            osg::ref_ptr<osgUtil::SceneView> sceneView;
            float viewport[4];                        // Win-size-relative [0,1]

            osg::ref_ptr<osgUtil::CameraManipulator>    _cameraManipulator;
            CameraManipList                             _cameraManipList;
        };

        typedef std::vector<ViewportDef> ViewportList;
        ViewportList _viewportList;
        unsigned int _focusedViewport;
                
        std::string                                 _saveFileName;
        
        bool _viewFrustumCullingActive;
        bool _smallFeatureCullingActive;

        int polymode;
        int texture;
        int backface;
        int lighting;
        int flat_shade;
        int _two_sided_lighting;
        float frRate; // gwm Jul 2001 added convolved ('averaged') frame rate
        int _printStats; // gwm Jul 2001 change from bool
        struct { // gwm Jul 2001, added for display of statistics
            float timeApp, timeCull, timeDraw, timeFrame;
            osg::Timer_t frameend;
        } times[3]; // store up to 3 frames worth of times
        bool _useDisplayLists;
        
        osg::Timer   _timer;
        osg::Timer_t _tickRatePerSecond;
        osg::Timer_t _initialTick;
        osg::Timer_t _lastFrameTick;
        osg::Timer_t _frameTick;

        // system tick.
        osg::Timer_t clockTick();
        osg::Timer_t frameTick();


        osg::ref_ptr<osg::FrameStamp>       _frameStamp;
        osg::ref_ptr<osg::DisplaySettings>  _displaySettings;


};

}

#endif                           // SG_VIEWIER_H
