/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Window class.
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef VIEW_WINDOW_HH
#define VIEW_WINDOW_HH 1

#define GET_WINDOW()        (Window::GetInstance())
#define GET_MAIN_VIEW()     (Window::GetInstance().GetMainView())
#define POST_REDISPLAY()    // NOP

#include <list>
#include "gfx/graphics.hh"
using namespace gfx;
#include "view/view.hh"

#include <osg/Object>
#include <osg/GraphicsContext>
#include <osg/OperationThread> // osg::Operation
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>
#include <osgViewer/GraphicsWindow>
#include <osgViewer/ViewerEventHandlers>  // StatsHandler

namespace view {

class View; class Manipulator;

////////////////////////////////////////////////////////////////////////////////
/// @brief Window contains Views, executes main loop, broadcasts draw events.
///
class Window
{
PREVENT_COPYING(Window)
private:
                            Window( const Vector2& pos, const WidthHeight<int>& wh, const string& title );
                            ~Window();
    CLASS_METHOD Window*    CreateInstance( void );

public:
    CLASS_METHOD Window&    GetInstance( void )
    {
        // NewInstance() gets ctor args from conf.
        if ( EX( msInstance != NULL ) )
            return *msInstance;
        else
            return *(msInstance = Window::CreateInstance());
    }
    void                    Make( void );
    void                    Reset( void );

// The main graphics loop:
public:
    void                    EnterMainLoop( void );

// Views:
public:
    enum { MAIN_VIEW = true, NOT_MAIN_VIEW = false };
    void                    AddView( shptr<View> view, const bool mainView = false );
    shptr<View>             GetMainView( void )
                            {
                            ASSERT( not mViews.empty() );
                                return mViews.front();
                            }
    bool                    SaveViewpoint( void );
    bool                    RestoreViewpoint( void );

// Info:
public:
    WidthHeight<int>        GetWindowSize( void );
    Rect<int>               GetWindowRect( void );
    Rect<int>               GetWindowPosition( void );
    uint                    GetFPS( void ) { return mFPS.ComputeFPS(); }

// OSG (LIMITED USE):
public:
    enum eCamera { eCamera_3D, eCamera_2D };
    void                              OsgAddCamera( RefPtr<osg::Camera> camera, const eCamera cameraType = eCamera_3D, const bool mainView = NOT_MAIN_VIEW );
    RefPtr<osgViewer::GraphicsWindow> OsgGetGraphicsWindow( void );
    void                              OsgRegisterEventHandler( RefPtr<osgGA::GUIEventHandler> eventHandler );
    void                              OsgSetStatsKey( const int key );

private:
    void                    ComputeFPS( const Milliseconds elapsedMilsec );
    void                    DoOperation( void );
    void                    DrawViewOutline( shptr<View> view, const RGBA outlineColor );

private:
    class Operation : public osg::Operation
    {
    public:
        Operation( void );
        virtual ~Operation();
        virtual void operator ()( osg::Object* );
    };

private:
    struct FPS
    {
                        FPS( void );
        void            Tick( const Milliseconds elapsedMilsec );
        uint            ComputeFPS( void ) { return mFPS; }

        uint            mFPS;           ///< FPS of previous second
        uint            mFrameCount;    ///< frame count of current second
        Milliseconds    mFrameStart;    ///< beginning of current second
    };

private:
    typedef std::list<shptr<View> > Views;
    CLASS_VAR Window*                       msInstance;         ///< there can be only one
    RefPtr<osgViewer::Viewer>               mViewer;            ///< contains cameras
    Views                                   mViews;             ///< Window contains one or more Views
    string                                  mTitle;             ///< window title
    FPS                                     mFPS;               ///< frame rate
    RefPtr<osg::GraphicsContext::Traits>    mTraits;
    RefPtr<osg::GraphicsContext>            mGraphicsContext;
    RefPtr<osgViewer::GraphicsWindow>       mGraphicsWindow;
    RefPtr<osg::Operation>                  mOperation;
    RefPtr0<osgViewer::StatsHandler>        mStatsHandler;      ///< statistics (might be disabled/NULL)
    RefPtr<Manipulator>                     mManipulator;       ///< custom view manipulator (OSG specific)
};

} // namespace view

#endif // VIEW_WINDOW_HH
