/*
 * This source file is part of KEOS (Free 3D Engine)
 * For the latest info, see http://www.keosengine.org/
 * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program 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 GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
 * http://www.gnu.org/copyleft/lesser.txt.
 *
 */

#ifndef KEOS_RENDERTARGET_H
#define KEOS_RENDERTARGET_H

#include "KeosPrerequisites.h"
#include "KeosRenderApp.h"

namespace Keos 
{
    //-----------------------------------------------------------------------
    /** A 'canvas' which can receive the results of a rendering operation.
     *  This abstract class defines a common root to all targets of rendering operations. A
     *  render target could be a window on a screen, or another
     *  offscreen surface like a texture or bump map etc.  
     */
    class KEOS_EXPORT IRenderTarget
    {
    public:
        enum StatFlags
        {
            SF_NONE           = 0,
            SF_FPS            = 1,
            SF_AVG_FPS        = 2,
            SF_BEST_FPS       = 4,
            SF_WORST_FPS      = 8,
            SF_TRIANGLE_COUNT = 16,
            SF_ALL            = 0xFFFF
        };

        struct FrameStats
        {
            float lastFPS;
            float avgFPS;
            float bestFPS;
            float worstFPS;
            unsigned long bestFrameTime;
            unsigned long worstFrameTime;
            size_t triangleCount;
        };

        /** Default constructor.
         */
        IRenderTarget();

        /** Destructor.
         */
        virtual ~IRenderTarget();

        /** Retrieve target's name.
         *  @return The target's name.
         */
        virtual const String& GetName(void) const;

        /** Retrieve information about the render target.
         *  @param nWidth Target's width.
         *  @param nHeight Target's height.
         *  @param nColourDepth Target's colour depth.
         */
        virtual void GetMetrics(uint& nWidth, uint& nHeight, uint& nColourDepth);

        virtual unsigned int GetWidth(void) const;
        virtual unsigned int GetHeight(void) const;
        virtual unsigned int GetColourDepth(void) const;

         /** Initialise the target.
         */
        virtual void Init(void);

        /** Tells the target to update it's contents.
         */
        virtual void Update(void);

        /** Retieves details of current rendering performance.
         *  @param
         *      lastFPS Pointer to a float to receive the number of frames per second (FPS)
         *      based on the last frame rendered.
         *  @param
         *      avgFPS Pointer to a float to receive the FPS rating based on an average of all
         *      the frames rendered since rendering began.
         *  @param
         *      bestFPS Pointer to a float to receive the best FPS rating that has been achieved
         *      since rendering began.
         *  @param
         *      worstFPS Pointer to a float to receive the worst FPS rating seen so far.
         */
        virtual void GetStatistics(float& lastFPS, float& avgFPS,
            float& bestFPS, float& worstFPS) const;  
        
        /** Individual stats access - gets the number of frames per second (FPS) based on the last frame rendered.
         */
        virtual float GetLastFPS() const;

        /** Individual stats access - gets the average frames per second (FPS) since call to Root::startRendering.
         */
        virtual float GetAverageFPS() const;

        /** Individual stats access - gets the best frames per second (FPS) since call to Root::startRendering.
         */
        virtual float GetBestFPS() const;

        /** Individual stats access - gets the worst frames per second (FPS) since call to Root::startRendering.
         */
        virtual float GetWorstFPS() const;

        /** Individual stats access - gets the best frame time
         */
        virtual float GetBestFrameTime() const;

        /** Individual stats access - gets the worst frame time
         */
        virtual float GetWorstFrameTime() const;

        /** Resets saved frame-rate statistices.
         */
        virtual void ResetStatistics(void);

        /** Used to retrieve the active state of the render target.
         */
        virtual bool IsActive() const;

        /** Used to set the active state of the render target.
         */
        virtual void SetActive( bool bState );

        /** Sets whether this target should be automatically updated if Keos's rendering
         *  loop or Keos::KeosRenderSystem::UpdateAllRenderTargets is being used.
         *  @param bAutoUpdate If true, the render target is updated during the automatic render
         *      loop or when Keos::KeosRenderSystem::UpdateAllRenderTargets is called. If false, the 
         *      target is only updated when its Update() method is called explicitly.
         */
        virtual void SetAutoUpdated(bool bAutoUpdate);
        
        /** Gets whether this target should be automatically updated if Keos's rendering
         *  loop or Keos::KeosRenderSystem::UpdateAllRenderTargets is being used.
         */
        virtual bool IsAutoUpdated(void) const;

		/** Gets the number of triangles rendered in the last Update() call. 
         */
		virtual size_t GetTriangleCount(void) const;

        /** Attaches a IRenderApp interface to render target.
         *  @param pRenderApp Interface for render of the target.
         */
        void SetRenderApp(IRenderApp* pRenderApp) { m_pRenderApp = pRenderApp; pRenderApp->m_pRenderTarget = this;}

    protected:

        /** Update stats.
         */
        void UpdateStats(void);

        //! The name of this target
        String m_strName;
		
        //! Interface for render of the target
        IRenderApp* m_pRenderApp;

        //! Target's width
        unsigned int m_nWidth;

        //! Target's height
        unsigned int m_nHeight;

        //! Target's colour depth
        unsigned int m_nColourDepth;

        //! Stats
		    FrameStats m_Stats;
      
        //! Timer for stats calculation
        CTimer* m_pTimer ;
       
        // Variables for stats claculation
        unsigned long m_nLastSecond;
        unsigned long m_nLastTime;
        size_t m_nFrameCount;

        //! The active state of the render target
        bool m_bActive;
        //! See SetAutoUpdated() function
        bool m_bAutoUpdate;

        bool m_bIsDepthBuffered;
    };

    //=======================================================================
    // IRenderTarget inline functions
    //=======================================================================

    //-----------------------------------------------------------------------
    inline const String& IRenderTarget::GetName(void) const
    {
        return m_strName;
    }

    //-----------------------------------------------------------------------
    inline uint IRenderTarget::GetWidth(void) const
    {
        return m_nWidth;
    }

    //-----------------------------------------------------------------------
    inline uint IRenderTarget::GetHeight(void) const
    {
        return m_nHeight;
    }

    //-----------------------------------------------------------------------
    inline uint IRenderTarget::GetColourDepth(void) const
    {
        return m_nColourDepth;
    }

    //-----------------------------------------------------------------------
    inline bool IRenderTarget::IsActive() const
    {
        return m_bActive;
    }

    //-----------------------------------------------------------------------
    inline void IRenderTarget::SetActive( bool bState )
    {
        m_bActive = bState;
    }

    //-----------------------------------------------------------------------
    inline void IRenderTarget::SetAutoUpdated(bool bAutoUpdate)
    {
        m_bAutoUpdate = bAutoUpdate;
    }

    //-----------------------------------------------------------------------
    inline bool IRenderTarget::IsAutoUpdated(void) const
    {
        return m_bAutoUpdate;
    }

    //-----------------------------------------------------------------------
    inline void IRenderTarget::GetStatistics(float& lastFPS, float& avgFPS,
        float& bestFPS, float& worstFPS) const
    {
        // Note - the will have been updated by the last render
        lastFPS = m_Stats.lastFPS;
        avgFPS = m_Stats.avgFPS;
        bestFPS = m_Stats.bestFPS;
        worstFPS = m_Stats.worstFPS;
    }

    //-----------------------------------------------------------------------
    inline float IRenderTarget::GetLastFPS() const
    {
        return m_Stats.lastFPS;
    }

    //-----------------------------------------------------------------------
    inline float IRenderTarget::GetAverageFPS() const
    {
        return m_Stats.avgFPS;
    }

    //-----------------------------------------------------------------------
    inline float IRenderTarget::GetBestFPS() const
    {
        return m_Stats.bestFPS;
    }

    //-----------------------------------------------------------------------
    inline float IRenderTarget::GetWorstFPS() const
    {
        return m_Stats.worstFPS;
    }
    
    //-----------------------------------------------------------------------
    inline size_t IRenderTarget::GetTriangleCount(void) const
    {
        return m_Stats.triangleCount;
    }

    //-----------------------------------------------------------------------
    inline float IRenderTarget::GetBestFrameTime() const
    {
        return m_Stats.bestFrameTime;
    }

    //-----------------------------------------------------------------------
    inline float IRenderTarget::GetWorstFrameTime() const
    {
        return m_Stats.worstFrameTime;
    }

} // Namespace Keos

#endif // KEOS_RENDERTARGET_H
