
#pragma warning( disable : 4786 )		// long names generated by STL

#include <windows.h>
#include <stdio.h>
#include <direct.h>
#include <io.h>

#include "PajaTypes.h"
#include "FactoryC.h"
#include "DllInterfaceC.h"
#include "ClassDescC.h"


using namespace PajaTypes;
using namespace PluginClass;


FactoryC::FactoryC()
{
	// empty
}

FactoryC::~FactoryC()
{
	// release all DLLs
	for( uint32 i = 0; i < m_rDlls.size(); i++ )
		delete m_rDlls[i];
}

void
FactoryC::load_plugins( const char* szDir )
{
	char	szOldDir[_MAX_PATH];
	bool	bValidOldDir = true;

	// get old directory before we chage to new
	if( _getcwd( szOldDir, _MAX_PATH ) == 0 )
		bValidOldDir = false;

	// change to plugin directory
	_chdir( szDir );

	long				hFile = 0;
	struct _finddata_t	rFileData;

	// check every file in plugin directory
	if( (hFile = _findfirst( "*.dll", &rFileData )) != -1 ) {
		do {
			char	szMsg[256];
			_snprintf( szMsg, 255, "FACTORY: Loading plugin %s...\n", rFileData.name );
			::OutputDebugString( szMsg );

			DllInterfaceC*	pIface = new DllInterfaceC;
			if( pIface->init( rFileData.name ) ) {

				_snprintf( szMsg, 255, "FACTORY: API version: %d.%d\n", pIface->get_api_version() >> 16, pIface->get_api_version() & 0xffff );
				::OutputDebugString( szMsg );

				if( pIface->get_api_version() == DEMOPAJA_VERSION ) {
					// store class descriptions from the DLL
					_snprintf( szMsg, 255, "FACTORY: %d classes\n", pIface->get_classdesc_count() );
					::OutputDebugString( szMsg );

					for( int32 i = 0; i < pIface->get_classdesc_count(); i++ ) {
						ClassDescC*	pClassDesc = pIface->get_classdesc( i );
						if( pClassDesc ) {
							_snprintf( szMsg, 255, "FACTORY:  * %s\n", pClassDesc->get_name() );
							::OutputDebugString( szMsg );

							DLLClassS	rClass;
							rClass.m_pClassDesc = pIface->get_classdesc( i );
							rClass.m_sClassDescDllName = rFileData.name;
							m_rDLLClasses.push_back( rClass );
						}
					}
					// store the DLL interface
					m_rDlls.push_back( pIface );
				}
				else {
					::OutputDebugString( "FACTORY: Failed, wrong API version.\n" );
					delete pIface;
				}
			}
			else {
				::OutputDebugString( "FACTORY: Failed to initialise DLL interface.\n" );
				delete pIface;
			}
		} while( _findnext( hFile, &rFileData ) == 0 );
		_findclose( hFile );
	}

	// change to old dir
	if( bValidOldDir )
		_chdir( szOldDir );
}


void*
FactoryC::create( const ClassIdC& rClassId )
{
	for( uint32 i = 0; i < m_rDLLClasses.size(); i++ ) {
		if( m_rDLLClasses[i].m_pClassDesc->get_class_id() == rClassId )
			return (void*)m_rDLLClasses[i].m_pClassDesc->create();
	}

	return 0;
}

uint32
FactoryC::get_classdesc_count()
{
	return m_rDLLClasses.size();
}

ClassDescC*
FactoryC::get_classdesc( uint32 ui32Index )
{
	if( ui32Index >= m_rDLLClasses.size() )
		return 0;
	return m_rDLLClasses[ui32Index].m_pClassDesc;
}

ClassDescC*
FactoryC::get_classdesc( const ClassIdC& rClassId )
{
	for( uint32 i = 0; i < m_rDLLClasses.size(); i++ )
		if( m_rDLLClasses[i].m_pClassDesc->get_class_id() == rClassId )
			return m_rDLLClasses[i].m_pClassDesc;
	return 0;
}

const char*
FactoryC::get_classdesc_dll_name( PajaTypes::uint32 ui32Index )
{
	if( ui32Index >= m_rDLLClasses.size() )
		return 0;
	return m_rDLLClasses[ui32Index].m_sClassDescDllName.c_str();
}

void
FactoryC::register_class( ClassDescC* pClass )
{
	DLLClassS	rDLLClass;
	rDLLClass.m_pClassDesc = pClass;
	rDLLClass.m_sClassDescDllName = "<internal>";
	m_rDLLClasses.push_back( rDLLClass );
}

