/*
 * 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.
 *
 */
#include "KeosRenderSystem.h"
#include "KeosRoot.h"
#include "KeosLogger.h"

namespace Keos
{
    //=======================================================================
    // IRenderSystem implementation
    //=======================================================================
    
    //-----------------------------------------------------------------------
    IRenderSystem::IRenderSystem()
    {
        m_pRenderWindow = NULL;

        m_pCapabilities = new CRenderSystemCapabilities();

        InitConfigOptions();
    }

    //-----------------------------------------------------------------------
    IRenderSystem::~IRenderSystem()
    {
        delete m_pCapabilities;
    }

    //-----------------------------------------------------------------------
    IRenderWindow* IRenderSystem::Initialise(bool bAutoCreateWindow, const String& strWindowTitle)
    {
        return NULL;
    }

    //-----------------------------------------------------------------------
    void IRenderSystem::Shutdown(void)
    {  
        CRoot::Instance().StopRendering();
          
        // Remove all the render targets.
        for( RenderTargetMap::iterator it = m_RenderTargets.begin(); it != m_RenderTargets.end(); ++it )
        {
            delete it->second;
        }
	    m_RenderTargets.clear();

        ILogger::Log("<-- Shutdown RenderSystem");
    }

    //-----------------------------------------------------------------------
    void IRenderSystem::DestroyRenderTarget(const String& strName)
    {
        IRenderTarget* rt = DetachRenderTarget(strName);
        delete rt;
    }

    //-----------------------------------------------------------------------
    IRenderTarget* IRenderSystem::GetRenderTarget( const String &strName )
    {
        RenderTargetMap::iterator it = m_RenderTargets.find( strName );
        IRenderTarget *ret = NULL;

        if( it != m_RenderTargets.end() )
        {
            ret = it->second;
        }

        return ret;
    }

    //-----------------------------------------------------------------------
    bool IRenderSystem::SetRenderApp(IRenderApp* pRenderApp, String& strTargetName)
    {
        RenderTargetMap::iterator it = m_RenderTargets.find( strTargetName );
        bool ret = false;
        if( it != m_RenderTargets.end() )
        {
            ret = true;
            it->second->SetRenderApp(pRenderApp);
        }
        return ret;
    }

    //-----------------------------------------------------------------------
    void IRenderSystem::AttachRenderTarget( IRenderTarget& target, bool bIsWindow )
    {  
        m_RenderTargets.insert( RenderTargetMap::value_type( target.GetName(), &target ) );
        if (bIsWindow)
          m_pRenderWindow = (IRenderWindow*)(&target);
    }

    //---------------------------------------------------------------------------------------------
    IRenderTarget* IRenderSystem::DetachRenderTarget( const String &strName )
    {
        RenderTargetMap::iterator it = m_RenderTargets.find( strName );
        IRenderTarget *ret = NULL;

        if( it != m_RenderTargets.end() )
        {
            ret = it->second;

            m_RenderTargets.erase( it );
        }

        return ret;
    }

    //-----------------------------------------------------------------------
    void IRenderSystem::InitAllRenderTargets(void)
    {
        // Init stats
        for(
            RenderTargetMap::iterator it = m_RenderTargets.begin();
            it != m_RenderTargets.end();
            ++it )
        {
            it->second->ResetStatistics();
            it->second->Init();
        }
    }

    //-----------------------------------------------------------------------
    void IRenderSystem::UpdateAllRenderTargets(void)
    {
        Assert(m_pRenderWindow != NULL);

        // Si on ferme la fenetre on arrete le rendu
        // Valide uniquement parcque il ne peut y avoir qu'une fenetre
        if (m_pRenderWindow->IsClosed())
            CRoot::Instance().StopRendering();

    	if( m_pRenderWindow->IsActive() && m_pRenderWindow->IsAutoUpdated())
        {
            BeginScene();
			m_pRenderWindow->Update();
            EndScene();
			m_pRenderWindow->SwapBuffers(false);
        }
      
		RenderTargetMap::iterator itarg, itargend;
		itargend = m_RenderTargets.end();
		for( itarg = m_RenderTargets.begin(); itarg != itargend; ++itarg )
		{
			if( m_pRenderWindow != itarg->second &&
            itarg->second->IsActive() && itarg->second->IsAutoUpdated())
            {
                BeginScene();
			    itarg->second->Update();
                EndScene();
            }
		}
    }

    //-----------------------------------------------------------------------
    void IRenderSystem::InitConfigOptions()
	{
		ConfigOption optVideoMode;
        ConfigOption optColorDepth;
		ConfigOption optFullScreen;
		ConfigOption optVSync;

		optVideoMode.name = "Video Mode";
		optVideoMode.currentValue = "640x480";
		optVideoMode.possibleValues.push_back( "320x200" );
        optVideoMode.possibleValues.push_back( "640x480" );
        optVideoMode.possibleValues.push_back( "800x600" );
        optVideoMode.possibleValues.push_back( "1024x768" );
        optVideoMode.possibleValues.push_back( "1280x1024" );
        optVideoMode.possibleValues.push_back( "1600x1200" );
		optVideoMode.immutable = false;

        optColorDepth.name = "Color Depth";
		optColorDepth.possibleValues.push_back( "16" );
		optColorDepth.possibleValues.push_back( "32" );
		optColorDepth.currentValue = "32";
		optColorDepth.immutable = false;

		optFullScreen.name = "Fullscreen";
		optFullScreen.possibleValues.push_back( "yes" );
		optFullScreen.possibleValues.push_back( "no" );
		optFullScreen.currentValue = "no";
		optFullScreen.immutable = false;

		//optVSync.name = "vsync";
		//optVSync.immutable = false;
		//optVSync.possibleValues.push_back( "yes" );
		//optVSync.possibleValues.push_back( "no" );
		//optVSync.currentValue = "no";

		m_Options[optVideoMode.name] = optVideoMode;
        m_Options[optColorDepth.name] = optColorDepth;
		m_Options[optFullScreen.name] = optFullScreen;
        //m_Options[optVSync.name] = optVSync;
	}

    //-----------------------------------------------------------------------
    void IRenderSystem::SetConfigOption(const String& strName, const String& strValue)
    {
        // Find option
        ConfigOptionMap::iterator it = m_Options.find(strName);

        // Update
        if( it != m_Options.end())
            it->second.currentValue = strValue;
        else
        {
            ILogger::Log("Option named \"%s\" does not exist !", strName.c_str());
        }
    }

	//-----------------------------------------------------------------------
	CGprofile IRenderSystem::GetShaderProfile(TShaderType Type) const
	{
		return Type == SHADER_VERTEX ? m_VSProfile : m_PSProfile;
	}


	//-----------------------------------------------------------------------
	const char* const* IRenderSystem::GetShaderOptions(TShaderType Type) const
	{
		return Type == SHADER_VERTEX ? m_VSOptions : m_PSOptions;
	}


} // namespace Keos
