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

#if KEOS_PLATFORM == KEOS_PLATFORM_WIN32
#   define WIN32_LEAN_AND_MEAN
#   include <windows.h>
#endif

namespace Keos 
{
    //=======================================================================
    // CDynLib implementation
    //=======================================================================

    //-----------------------------------------------------------------------
    CDynLib::CDynLib( const String& strName )
    {
        m_strName = strName;
        m_hInst = NULL;
    }

    //-----------------------------------------------------------------------
    CDynLib::~CDynLib()
    {
    }

    //-----------------------------------------------------------------------
    void CDynLib::Load()
    {
        // Log library load
        ILogger::Log("Loading library %s", m_strName.c_str());

		String strName = m_strName;
#if KEOS_PLATFORM == KEOS_PLATFORM_LINUX
        // dlopen() does not add .so to the filename, like windows does for .dll
        if (strName.substr(strName.length() - 3, 3) != ".so")
           strName += ".so";
#endif
        m_hInst = (DYNLIB_HANDLE)DYNLIB_LOAD( strName.c_str() );

        if( !m_hInst )
        {
            DYNLIB_EXCEPT(m_strName, 
            "Could not load dynamic library " + m_strName +  "\nSystem Error: " + DynlibError(),
            "CDynLib::Load");
        }
    }

    //-----------------------------------------------------------------------
    void CDynLib::Unload()
    {
        // Log library load
        ILogger::Log("Unloading library %s", m_strName.c_str());

        if( DYNLIB_UNLOAD( m_hInst ) )
		{
            DYNLIB_EXCEPT(m_strName, 
            "Could not unload dynamic library " + m_strName +  "\nSystem Error: " + DynlibError(),
            "CDynLib::Unload");
		}
    }

    //-----------------------------------------------------------------------
    void* CDynLib::GetSymbol( const String& strName ) const throw()
    {
        return (void*)DYNLIB_GETSYM( m_hInst, strName.c_str() );
    }

    //-----------------------------------------------------------------------
    String CDynLib::DynlibError( void ) 
    {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        LPVOID lpMsgBuf; 
        FormatMessage( 
            FORMAT_MESSAGE_ALLOCATE_BUFFER | 
            FORMAT_MESSAGE_FROM_SYSTEM | 
            FORMAT_MESSAGE_IGNORE_INSERTS, 
            NULL, 
            GetLastError(), 
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
            (LPTSTR) &lpMsgBuf, 
            0, 
            NULL 
            ); 
        String ret = (char*)lpMsgBuf;
        // Free the buffer.
        LocalFree( lpMsgBuf );
        return ret;
#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX
        return String(dlerror());
#elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE
        return String(mac_errorBundle());
#else
        return String("");
#endif
    }
} // namespace Keos
