#include "Mix/Module.h"
#include <map>

using namespace Mix;

class Module::Impl
{
public:
	HMODULE m_hModule;
	std::map<Mix::String, void*> m_FunctionMap;

public:
	MIX_DECLARE_ALLOCATOR();
};

Module::Module( void ) :
m_pImpl( MIX_LIB_NEW_T( Mix::Memory::SECTION_GENERAL, Module::Impl ) )
{
}

Module::~Module( void )
{
	Unload();
	MIX_LIB_DELETE_T( Impl, m_pImpl );
}

Boolean Module::Load( const wchar_t* moduleName )
{
	m_pImpl->m_hModule = ::LoadLibrary( moduleName );

	return ( m_pImpl->m_hModule != NULL );
}

void Module::Unload( void )
{
	if( m_pImpl->m_hModule != NULL )
	{
		::FreeLibrary( m_pImpl->m_hModule );
		m_pImpl->m_hModule = NULL;
		m_pImpl->m_FunctionMap.clear();
	}
}

Boolean Module::RegisterFunction( const wchar_t* functionName )
{
	if( m_pImpl->m_hModule == NULL )
	{
		return False;
	}

	if( m_pImpl->m_FunctionMap.find( functionName ) != m_pImpl->m_FunctionMap.end() )
	{
		return True;
	}

	Mix::StringA fnAnsi;
	void* procAddr;

	fnAnsi = functionName;

	procAddr = ::GetProcAddress( m_pImpl->m_hModule, fnAnsi.GetConstPtr() );
	if( procAddr == NULL )
	{
		return False;
	}

	m_pImpl->m_FunctionMap.insert( std::pair<Mix::String, void*>( functionName, procAddr ) );

	return True;
}

void* Module::GetFunction( const wchar_t* functionName )
{
	std::map<Mix::String, void*>::iterator it;

	it = m_pImpl->m_FunctionMap.find( functionName );
	if( it == m_pImpl->m_FunctionMap.end() )
	{
		return NULL;
	}

	return it->second;
}
