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

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

#include <osgGA/GUIEventAdapter>
#include <osgGA/CameraManipulator>
#include <osgGA/GUIEventHandler>
#include <osgGA/AnimationPathManipulator>

#include <osgUtil/SceneView>

#include <osgGLUT/Window>

#include <list>
#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 osgGA::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 unsigned int addViewport(osgUtil::SceneView* sv,
                                 float x     = 0.0, float y      = 0.0,        
                                 float width = 1.0, float height = 1.0);

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

        unsigned 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 update(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(osgGA::CameraManipulator* cm,
					       unsigned int viewport = 0);
        void selectCameraManipulator(unsigned int pos, 
				     unsigned int viewport = 0);

	/// Set focusable
	void setFocusable( unsigned int viewp, bool focusable )
	{ _viewportList[viewp]._focusable = focusable; };

        void prependEventHandler(osgGA::GUIEventHandler* handler,unsigned int viewport = 0);
        void appendEventHandler(osgGA::GUIEventHandler* handler,unsigned int viewport = 0);

        // derived from osgGA::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);
	virtual void requestShutdown() { exit(1); };

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

        void setDisplaySettings(osg::DisplaySettings* ds) { _displaySettings = ds; }
        osg::DisplaySettings* getDisplaySettings() { return _displaySettings.get(); }
        const osg::DisplaySettings* getDisplaySettings() const { return _displaySettings.get(); }

        typedef std::vector<osg::ref_ptr<osgGA::CameraManipulator> > CameraManipList;
        typedef std::list<osg::ref_ptr<osgGA::GUIEventHandler> > EventHandlerList;


        void setRecordingAnimationPath(bool on) { _recordingAnimationPath = on; }
        bool getRecordingAnimationPath() const { return _recordingAnimationPath; }

        void setAnimationPath(osg::AnimationPath* path) { _animationPath = path; }
        osg::AnimationPath* getAnimationPath() { return _animationPath.get(); }
        const osg::AnimationPath* getAnimationPath() const { return _animationPath.get(); }

        int mapWindowXYToViewport(int x, int y);

    protected:

        virtual void clear();

        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(int key, int x, int y, bool keydown = true);

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

        static Viewer*    s_theViewer;


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

	    bool _focusable;

            osg::ref_ptr<osgGA::CameraManipulator>      _cameraManipulator;
            CameraManipList                             _cameraManipList;
            
	    EventHandlerList                            _eventHandlerList;
        };

        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;
        float frRate; // gwm Jul 2001 added convolved ('averaged') frame rate
        int _printStats; // gwm Jul 2001 change from bool
        
        struct StatsRecord
        { // gwm Jul 2001, added for display of statistics
            StatsRecord():
                timeUpdate(0), timeCull(0), timeDraw(0), timeFrame(0),
                frameend(0) {}
        
            float timeUpdate, timeCull, timeDraw, timeFrame;
            osg::Timer_t frameend;
        };
        StatsRecord times[3]; // store up to 3 frames worth of times
        
        bool _useDisplayLists;
        
        osg::Timer   _timer;
        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;

        bool                                _recordingAnimationPath;
        osg::ref_ptr<osg::AnimationPath>    _animationPath;


};

}

#endif                           // SG_VIEWIER_H
