/////////////////////////////////////////////////////////////////////////////
// File:        coreruntimeimpl.cpp
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Copyright:   (C) 2010-10 Cesar Mauri Loba - CREA Software Systems
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 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 General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////
#include "spcore/coreruntime.h"
#include "spcore/coreversion.h"
#include "spcore/pinimpl.h"
#include "spcore/basetype.h"
#include "spcore/basictypes.h"
#include "spcore/iterator.h"
#include "spcore/pin.h"
#include "spcore/component.h"
#include "spcore/module.h"
#include "configurationimpl.h"


#include <algorithm>
#include <iostream>
#include <Poco/SharedLibrary.h>
#include <Poco/Exception.h>
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/static_assert.hpp>

#ifdef ENABLE_WXWIDGETS
#include <wx/app.h>
#include <wx/image.h>
#include <wx/event.h>
#include "pathsimpl.h"
#include <errno.h>

using namespace spcore;
using namespace std;

#ifdef WIN32
#include <io.h>
#include <fcntl.h>
#define pipe(x) _pipe(x,sizeof(int),_O_BINARY)
#endif

//
// Custom event to forward secondary threads requests
//
DEFINE_EVENT_TYPE( wxEVT_SPCORE_MESSAGE_SYNC )

class SpcoreMessageEventSync : public wxEvent
{
public:
	SpcoreMessageEventSync (SmartPtr<const CTypeAny> msg, IInputPin & destPin, int pipeWrite)
	: wxEvent (0, wxEVT_SPCORE_MESSAGE_SYNC)
	, m_message(msg)
	, m_destPin(&destPin)
	, m_pipeWrite(pipeWrite)
	{
	}

	SmartPtr<const CTypeAny> GetMessage() const { return m_message; }
	IInputPin & GetInputPin() const { return *m_destPin; }
	int GetPipeWrite() const { return m_pipeWrite; }

	virtual wxEvent* Clone() const
	{
		return new SpcoreMessageEventSync(*this);
	}

private:
	SmartPtr<const CTypeAny> m_message;
	IInputPin * m_destPin;
	// pipe write end to notify when the request has been completed
	int m_pipeWrite;
};

DEFINE_EVENT_TYPE( wxEVT_SPCORE_MESSAGE_ASYNC )

class SpcoreMessageEventAsync : public wxEvent
{
public:
	SpcoreMessageEventAsync (const CTypeAny& msg, IComponent& compo, ICoreRuntime::ToMainThreadCallback* cb)
	: wxEvent (0, wxEVT_SPCORE_MESSAGE_ASYNC)
	, m_message(&msg)
	, m_component(&compo)
	, m_callback(cb)
	{
		assert (cb);
	}

	const CTypeAny& GetMessage() const { return *m_message; }
	IComponent& GetComponent() const { return *m_component; }
	ICoreRuntime::ToMainThreadCallback* GetCallback() const { return m_callback; }

	virtual wxEvent* Clone() const
	{
		return new SpcoreMessageEventAsync(*m_message, *m_component, m_callback);
	}

private:
	SmartPtr<const CTypeAny> m_message;
	SmartPtr<IComponent> m_component;
	ICoreRuntime::ToMainThreadCallback* m_callback;
};


/*
	To provide support for wxWidgets we need an wxApp object along with
	a custom filter which also processes internal SITPLUS events
*/

class SPwxApp: public wxApp
{
	DECLARE_CLASS( SPwxApp )
public:
	// Constructor
	SPwxApp() {}

private:
	virtual bool OnInit() {
		#if wxUSE_XPM
			wxImage::AddHandler(new wxXPMHandler);
		#endif
		#if wxUSE_LIBPNG
			wxImage::AddHandler(new wxPNGHandler);
		#endif
		#if wxUSE_LIBJPEG
			wxImage::AddHandler(new wxJPEGHandler);
		#endif
		#if wxUSE_GIF
			wxImage::AddHandler(new wxGIFHandler);
		#endif

		return wxApp::OnInit();
		// return true;
	}

	virtual int FilterEvent (wxEvent& event)
	{
		assert (wxThread::IsMain());
		if (event.GetEventType()== wxEVT_SPCORE_MESSAGE_ASYNC) {
			SpcoreMessageEventAsync & spevt= static_cast<SpcoreMessageEventAsync &>(event);

			ICoreRuntime::ToMainThreadCallback* callback= spevt.GetCallback();

			callback(&spevt.GetComponent(), &spevt.GetMessage ());

			return true;
		}
		else if (event.GetEventType()== wxEVT_SPCORE_MESSAGE_SYNC) {

			// Send the message within the main thread
			SpcoreMessageEventSync & spevt= static_cast<SpcoreMessageEventSync &>(event);
			int send_result= spevt.GetInputPin().Send (spevt.GetMessage());

			// send result through the pipe, this also let us to make the secondary
			// thread until the request is completed
	write_pipe:
			int write_result= write (spevt.GetPipeWrite(), &send_result, sizeof(send_result));

			// sizeof(int) means a correctly performed write operation which is
			// the common case, so just return
			if (write_result== sizeof(int)) return true;

			// We just accept an interruption of the write operation. Retry.
			if (write_result== -1 && errno== EINTR) goto write_pipe;

			// In others cases a fatal error occured
			getSpCoreRuntime()->LogMessage (ICoreRuntime::LOG_FATAL, "unexpected error writing to pipe", "spcore");

			// return true anyway to notify that this event has been processed
			return true;
		}

		return -1;
	}
};

IMPLEMENT_CLASS( SPwxApp, wxApp )

#endif

namespace spcore {

//
// Provided component and its factory that allows to compose other components
//
class CCompositeComponent : public CCompositeComponentAdapter {
public:
    CCompositeComponent(const char * name, int argc, const char * argv[])
    : CCompositeComponentAdapter(name, argc, argv) {}
	virtual const char* GetTypeName() const {
		return CCompositeComponent::getTypeName();
	}
	static const char* getTypeName() { return "component_composer"; }

};

class CCompositeComponentFactory : public IComponentFactory {
public:
	virtual const char* GetName() const {
		return CCompositeComponent::getTypeName();
	}
	virtual SmartPtr<IComponent> CreateInstance(const char * name, int argc, const char * argv[]) {
		return  SmartPtr<IComponent>(new CCompositeComponent(name, argc, argv), false);
	}
};

//
// Internal implementation of ICoreRuntime
//
class CCoreRuntime : public ICoreRuntime {
public:
	CCoreRuntime();

    virtual ~CCoreRuntime();

    virtual int ResolveTypeID(const char * name);

    virtual SmartPtr<IIterator<ITypeFactory*> > QueryTypes();

    virtual SmartPtr<CTypeAny> CreateTypeInstance(const char * typeName);

    virtual SmartPtr<CTypeAny> CreateTypeInstance(int id);

    virtual SmartPtr<IIterator<IComponentFactory*> > QueryComponents();

    virtual SmartPtr<IComponent> CreateComponent(const char * typeName, const char * name, int argc, const char * argv[]);

	virtual SmartPtr<IOutputPin> CreateOutputPin(const char* type, const char* name, bool locked);

    virtual int RegisterModule(SmartPtr<IModule> module);

	virtual int LoadModule(const char * name, const char * dir= NULL);

	virtual void LogMessage (LogSeverityLevel severity, const char* message, const char* module= NULL);

	virtual void RegisterLogTarget (ILogTarget* lt);

	virtual void UnregisterLogTarget (ILogTarget* lt);

	virtual IPaths& GetPaths() const {
		static SmartPtr<IPaths> p(new Paths, false);
		return *p;
	}

	virtual SmartPtr<IConfiguration> GetConfiguration() const {
		return SmartPtr<IConfiguration>(new ConfigurationLibconfig(), false);
	}

	virtual bool IsMainThread () const {
		return (boost::this_thread::get_id()== m_mainThreadId);
	}

    

#ifdef ENABLE_WXWIDGETS
	virtual int InitGUISupport (int argc, char** argv) {
		// Sanity checks
		assert (wxThread::IsMain());
		if (m_wxInitialized) {
			LogMessage (LOG_ERROR, "wxWidgets GUI support already initialized. Ignoring request", "spcore");
			return 0;
		}

		// Set our own wxApp implementation
		wxApp::SetInstance( new SPwxApp() );

		// Initializes wx
		if (!wxEntryStart( argc, argv )) return -1;

		// Call OnInit
		wxTheApp->OnInit();

		// wx has been initialized
		m_wxInitialized= true;

		return 0;
	}

	virtual int RunMessageLoop () {
		// Sanity checks
		assert (m_wxInitialized);
		assert (wxThread::IsMain());
		if (!m_wxInitialized) {
			LogMessage (LOG_FATAL, "wxWidgets GUI support NOT iniatilized", "spcore");
			return -1;
		}

		// Run wx main loop. This call does not return until last frame has been closed
		int retval= wxTheApp->OnRun();

		// Close all open write ends of the pipes to allow threads to continue execution
		boost::mutex::scoped_lock lock(m_pipeWriteEndMutex);
		std::vector<int>::iterator it= m_pipeWriteEnd.begin();
		for (;it!= m_pipeWriteEnd.end(); ++it) close (*it);
		m_pipeWriteEnd.clear();

		return retval;
	}

	virtual void CleanupGUISupport () {
		// Sanity checks
		assert (m_wxInitialized);
		if (!m_wxInitialized) return;
		assert (wxThread::IsMain());

		// wx cleanup
		wxEntryCleanup();

		// wx no longer initialized
		m_wxInitialized= false;
	}

	virtual int SendMessageMainThreadSync (SmartPtr<const CTypeAny> msg, IInputPin & dst) {
		// If this thread is already the main one simply send the message
		if (IsMainThread()) dst.Send(msg);
		

		// Sanity checks
		assert (m_wxInitialized);
		if (!m_wxInitialized) {
			LogMessage (LOG_FATAL, "wxWidgets GUI support NOT initialized", "spcore");
			return -1;
		}

		// Check whether thread specific memory area has been initialitzed
		if (mt_pipeEnds.get()== NULL) {
			// Initialize memory
			mt_pipeEnds.reset(new CCoreRuntime::PipeEnds);
			mt_pipeEnds->fd_read= -1;
			mt_pipeEnds->fd_write= -1;

			// Create pipe
			if (pipe ((int *) mt_pipeEnds.get())) {
				LogMessage (LOG_FATAL, "cannot create pipe", "spcore");
				mt_pipeEnds.reset();
				return -1;
			}

			assert (mt_pipeEnds->fd_read!= -1);
			assert (mt_pipeEnds->fd_write!= -1);

			// Add the pipe write end to the vector
			boost::mutex::scoped_lock lock(m_pipeWriteEndMutex);

#ifndef NDEBUG
			// In debuhg mode also check that the fd doesn't exists
			std::vector<int>::iterator it=
				::find(m_pipeWriteEnd.begin(), m_pipeWriteEnd.end(), mt_pipeEnds->fd_write);
			assert(it== m_pipeWriteEnd.end());
#endif
			m_pipeWriteEnd.push_back (mt_pipeEnds->fd_write);
		}

		// Send message to the main loop
		SpcoreMessageEventSync evt(msg, dst, mt_pipeEnds->fd_write);
		::wxPostEvent (wxTheApp, evt);

		// Wait until request is completed
		int exitCode;
read_pipe:
		int retval= read(mt_pipeEnds->fd_read, &exitCode, sizeof(int));

		// sizeof(int) means a correctly performed read operation which is
		// the common case, so just return the provided return code
		if (retval== sizeof(int)) return exitCode;

		// 0 means EOF. The write end of the pipe has been closed. This
		// happens as part of the normal application shutdown. Just ignore
		// although we say that the operation has not been performed
		if (retval== 0) return -1;

		// we expect atomic reads of full integers each time. Shouldn't happen
		if (retval > 0 && retval < static_cast<int>(sizeof(int))) {
			LogMessage (LOG_FATAL, "unexpected size reading from pipe", "spcore");
			return -1;
		}

		// At this point the only option is that read failed
		assert (retval== -1);

		// We just accept an interrution of the read operation and retry.
		if (errno== EINTR) goto read_pipe;

		// Otherwise log a fatal error
		LogMessage (LOG_FATAL, "unexpected error reading from pipe", "spcore");

		return -1;
	}

	// Removes a specific file descriptor from vector of pipes write end
	// Return true if successfully removed or false if not found
	// Note that if the vector is empty means that all descriptors
	// have been closed as part of the normal shutdown process
	bool CleanupPipeEnd (int pipeWrite) {
		assert (!wxThread::IsMain());

		boost::mutex::scoped_lock lock(m_pipeWriteEndMutex);

		// Vector empty, normal situation, just return
		if (m_pipeWriteEnd.size()== 0) return false;

		// Find file descriptor
		std::vector<int>::iterator it=
			::find(m_pipeWriteEnd.begin(), m_pipeWriteEnd.end(), pipeWrite);


		if (it!= m_pipeWriteEnd.end()) {
			// Found. Remove and close.
			m_pipeWriteEnd.erase (it);
			close (pipeWrite);
			return true;
		}
		else {
			// Not found. Shouldn't happen. Log error.
			LogMessage (LOG_FATAL, "CleanupPipeEnd: descriptor not found", "spcore");
			assert (false);
			return false;
		}
	}

	//
	// Attributtes
	//
	struct PipeEnds {
		int fd_read;
		int fd_write;
	};
	BOOST_STATIC_ASSERT(sizeof(PipeEnds) == sizeof(int)*2);

	virtual void SendMessageMainThreadAsync (const CTypeAny& msg, IComponent& compo, ToMainThreadCallback* cb) {
		assert (!wxThread::IsMain());

		SpcoreMessageEventAsync evt(msg, compo, cb);			
		::wxPostEvent (wxTheApp, evt);
	}

private:
	// Local thread storage for the pipe ends
	boost::thread_specific_ptr<PipeEnds> mt_pipeEnds;

	bool m_wxInitialized;

	// Vector to stored write ends of pipes, used on termination
	std::vector<int> m_pipeWriteEnd;
	boost::mutex m_pipeWriteEndMutex;
#endif

private:

	//
	// Private methods
	//

	// Check if a module with the same name exists
	bool ExistsModule (const char * name) {
		assert (name);
		// Lookup module name
		map<string,IModule*>::iterator it= m_modules.find(name);
		return (it!= m_modules.end());
	}

	// Check if a type exists or not
	bool ExistsType (const char * name) {
		assert (name);
		return (ResolveTypeID(name)!= TYPE_INVALID);
	}

	// Check if a component exists
	bool ExistsComponent (const char * name) {
		assert (name);
		return (m_componentFactories.find(name)!= m_componentFactories.end());
	}

	// Register a type
	void AddType (ITypeFactory& tf) {
		assert (!ExistsType(tf.GetName()));
		tf.AddRef();
		m_typeFactories.push_back (&tf);
  		m_name2TypeID.insert(pair<const char *,int>(tf.GetName(), m_typeFactories.size()));
	}

	// Register a component
	void AddComponent (IComponentFactory& cf) {
		assert (!ExistsComponent(cf.GetName()));
		cf.AddRef();
		m_componentFactories.insert(pair<const char *,IComponentFactory*>(cf.GetName(), &cf));
	}

	// Register a module
	void AddModule (IModule& m) {
		assert (!ExistsModule (m.GetName()));
		m.AddRef();
		m_modules.insert(pair<string, IModule*>(m.GetName(), &m));
	}

	//
	// Types
	//
	map<string,int> m_name2TypeID;
	vector<ITypeFactory*> m_typeFactories;

	//
	// Data members
	//

	// Components
    map<string,IComponentFactory*> m_componentFactories;

	// Modules
    map<string,IModule*> m_modules;
    vector<Poco::SharedLibrary*> m_sharedLibraries;

	// Data dir
	//mutable std::string m_dataDir;

    boost::recursive_mutex m_mutex;
	boost::thread::id m_mainThreadId;

	// Log support
	boost::mutex m_logMutex;
	vector<ILogTarget*> m_logTargets;
};

typedef IModule*     module_create_instance();

#ifdef ENABLE_WXWIDGETS
// cleanup routine called after each thread has ended
// TODO: check if this works with non boost threads
void cleanup_pipe_ends(CCoreRuntime::PipeEnds * pends)
{
	if (pends->fd_read!= -1)
		close (pends->fd_read);
	if (pends->fd_write!= -1)		
		static_cast<CCoreRuntime *>(getSpCoreRuntime())->CleanupPipeEnd (pends->fd_write);
	delete pends;
}

#endif		// ENABLE_WXWIDGETS

CCoreRuntime::CCoreRuntime()
#ifdef ENABLE_WXWIDGETS
: mt_pipeEnds(cleanup_pipe_ends)
, m_wxInitialized(false)
#endif
{
	// Assume that the core runtime is initialized from the main thread
	// we record the ID to know wether a call comes from the main thread
	m_mainThreadId= boost::this_thread::get_id();

	// Add type ANY for translation but doesn't populate factory
	m_name2TypeID.insert(pair<const char *,int>("any",  TYPE_ANY));

	// Register base types
	int retval= RegisterModule(SmartPtr<IModule>(new CBasicTypesModule(), false));
	assert (retval== 0);

	// Add composite component
	IComponentFactory* component=new CCompositeComponentFactory();
	AddComponent (*component);
	component->Release();
}

CCoreRuntime::~CCoreRuntime(){
	{
		// Type factories
		vector<ITypeFactory*>::iterator it(m_typeFactories.begin());
		for (;it!= m_typeFactories.end(); ++it) (*it)->Release();
		m_typeFactories.clear();
	}

	{
		// Component factories
		map<string,IComponentFactory*>::iterator it(m_componentFactories.begin());
		for (;it!= m_componentFactories.end(); ++it) it->second->Release();
		m_componentFactories.clear();
	}

	{
		// Delete modules
		map<string,IModule *>::iterator it(m_modules.begin());
		//for(itm= m_modules.begin(); itm!= m_modules.end(); ++itm) itm->second->Release();
		for (;it!= m_modules.end(); ++it) it->second->Release();
		m_modules.clear();
	}

	{
		// Delete shared libraries
		vector<Poco::SharedLibrary*>::iterator it(m_sharedLibraries.begin());
		for (; it!= m_sharedLibraries.end(); ++it) {
			(*it)->unload();
			delete (*it);
		}
		m_sharedLibraries.clear();
	}
#ifdef ENABLE_WXWIDGETS
	assert (m_pipeWriteEnd.size()== 0);
#endif
}

// Resolves the runtime ID of a named type. Returns the ID or TYPE_INVALID
// if the specified type doesn't exists.
int CCoreRuntime::ResolveTypeID(const char * name) {
	boost::recursive_mutex::scoped_lock lock(m_mutex);

	map<string,int>::iterator it= m_name2TypeID.find(name);
	return (it!= m_name2TypeID.end() ? it->second : TYPE_INVALID);
}

SmartPtr<IIterator<ITypeFactory*> > CCoreRuntime::QueryTypes() {
  	boost::recursive_mutex::scoped_lock lock(m_mutex);

	return SmartPtr<IIterator<ITypeFactory*> > (new CIteratorVector<ITypeFactory*>(m_typeFactories), false);
}

// Creates a new type instance for a given type name. Returns a pointer
// to the new instance or NULL if the type doesn't exists or another error
// occurred.
SmartPtr<CTypeAny> CCoreRuntime::CreateTypeInstance(const char * typeName) {
	boost::recursive_mutex::scoped_lock lock(m_mutex);

	return CreateTypeInstance(ResolveTypeID(typeName));
}

SmartPtr<CTypeAny> CCoreRuntime::CreateTypeInstance(int id) {
  	boost::recursive_mutex::scoped_lock lock(m_mutex);

	if (id< 1) return NULL;
  	if ((unsigned int) id> m_typeFactories.size()) return NULL;
  	return m_typeFactories[id-1]->CreateInstance(id);
}

SmartPtr<IIterator<IComponentFactory*> > CCoreRuntime::QueryComponents() {
	boost::recursive_mutex::scoped_lock lock(m_mutex);

	return SmartPtr<IIterator<IComponentFactory*> >
		(new CIteratorMap<string,IComponentFactory*>(m_componentFactories), false);
}

SmartPtr<IComponent> CCoreRuntime::CreateComponent(const char * typeName, const char * name, int argc, const char * argv[]) {
  	boost::recursive_mutex::scoped_lock lock(m_mutex);

	// Lookup component type name
  	map<string,IComponentFactory*>::iterator it;
  	it= m_componentFactories.find(typeName);
  	if (it== m_componentFactories.end()) return NULL;	// Component type not found

	return it->second->CreateInstance(name, argc, argv);
}

SmartPtr<IOutputPin> CCoreRuntime::CreateOutputPin(const char* type, const char* name, bool locked)
{
	SmartPtr<IOutputPin> retval;

	int typeID= this->ResolveTypeID(type);
	if (typeID!= TYPE_INVALID) {
		try {
			// Really not needed the try block because we know that the type
			// name exists. Just to be safe.
			if (!locked)
				retval= SmartPtr<IOutputPin>(new COutputPin (name, type), false);
			else
				retval= SmartPtr<IOutputPin>(new COutputPinLock (name, type), false);
		}
		catch(...) {}
	}

	return retval;
}

int CCoreRuntime::RegisterModule(SmartPtr<IModule> module) {
  	boost::recursive_mutex::scoped_lock lock(m_mutex);

	//
	// Sanity checks
	//

	// Lookup module name. Error if already registered
	{
		const char* name= module->GetName();
		if (name== NULL || *name== '\0') return -5;
		if (ExistsModule(name)) return -1;
	}

    // Check api version number
  	if (module->GetCoreVersion()!= SPCORE_VERSION)
  		return -2;	// Wrong core version

  	// Check types
	SmartPtr<IIterator<ITypeFactory*> > ittf= module->GetTypeFactories();
  	if (ittf.get())
		for (ittf->First(); !ittf->IsDone(); ittf->Next()) {
			const char* name= ittf->CurrentItem()->GetName();
			if (name== NULL || *name== '\0') return -5;
			// Error if type name already registered
			if (ExistsType(name)) return -3;
		}

  	// Check component
  	SmartPtr<IIterator<IComponentFactory*> > itcf= module->GetComponentFactories();
  	if (itcf.get())
		for (itcf->First(); !itcf->IsDone(); itcf->Next()) {
			const char* name= itcf->CurrentItem()->GetName();
			if (name== NULL || *name== '\0') return -5;
			// Error if component already registered
			if (ExistsComponent(name)) return -4;
		}

	//
	// Register elements
	//

	// Register types
	if (ittf.get())
  		for (ittf->First(); !ittf->IsDone(); ittf->Next())
			AddType (*ittf->CurrentItem());

   	// Register components
  	if (itcf.get())
  		for (itcf->First(); !itcf->IsDone(); itcf->Next())
			AddComponent (*itcf->CurrentItem());

  	// Register the module itself
	AddModule (*module);

  	return 0;
}

int CCoreRuntime::LoadModule(const char * name, const char * dir) {
	boost::recursive_mutex::scoped_lock lock(m_mutex);

	std::string fullPath;
	if (dir) {
		fullPath.append(dir);
		fullPath.append("/");
	}

#if !defined (WIN32)
	// We assume *NIX system
	// TODO: check for Mac
	fullPath.append("lib");
#endif
	fullPath.append(name);
#if defined (WIN32)
	fullPath.append(".dll");
#else
	fullPath.append(".so");
#endif

	Poco::SharedLibrary* sl= NULL;

	try {
		sl= new Poco::SharedLibrary (fullPath.c_str());
	}
	catch (Poco::LibraryLoadException& e) {
		// Library cannot be loaded
		std::string message(e.displayText());
		LogMessage (LOG_ERROR, message.c_str(), "spcore");
		return -6;
	}
	catch (Poco::LibraryAlreadyLoadedException) {
		return -1;
	}

	// Get library entry point
	if (!sl->hasSymbol("module_create_instance")) {
		delete sl;
		return -7;
	}
	module_create_instance* mci= reinterpret_cast<module_create_instance*>(sl->getSymbol("module_create_instance"));

	// Get IModule instance
	IModule *mod= mci();
	if (mod== NULL) {
		delete sl;
		return -8;
	}

	// Register module
	int retval= RegisterModule(SmartPtr<IModule>(mod, false));

	if (retval< 0) delete sl;
	else this->m_sharedLibraries.push_back(sl);

	return retval;
}


void CCoreRuntime::LogMessage (LogSeverityLevel severity, const char* message, const char* module)
{
	boost::mutex::scoped_lock lock(m_logMutex);

	if (m_logTargets.empty()) {
		switch (severity) {
			case LOG_DEBUG: std::cerr << "DEBUG:"; break;
			case LOG_INFO: std::cerr << "INFO:"; break;
			case LOG_WARNING: std::cerr << "WARNING:"; break;
			case LOG_ERROR: std::cerr << "ERROR:"; break;
			case LOG_FATAL: std::cerr << "FATAL:"; break;
			default: assert (false);
		}

		if (module)
			std::cerr << module << ":";

		std::cerr << message << std::endl;
	}
	else {
		string theMessage;
		if (module) { 
			theMessage+= module;
			theMessage+= ". ";
		}

		theMessage+= message;

		vector<ILogTarget*>::iterator it= m_logTargets.begin();
		for (; it!= m_logTargets.end(); ++it) (*it)->LogMessage(severity, theMessage.c_str());
	}
}

void CCoreRuntime::RegisterLogTarget (ILogTarget* lt)
{
	boost::mutex::scoped_lock lock(m_logMutex);

	vector<ILogTarget*>::const_iterator it= 
		find (m_logTargets.begin(), m_logTargets.end(), lt);

	if (it!= m_logTargets.end()) 
		// Already registered, ignore request
		return;

	m_logTargets.push_back(lt);
}

void CCoreRuntime::UnregisterLogTarget (ILogTarget* lt)
{
	boost::mutex::scoped_lock lock(m_logMutex);

	vector<ILogTarget*>::iterator it= 
		find (m_logTargets.begin(), m_logTargets.end(), lt);

	if (it== m_logTargets.end()) 
		// Not registered, ignore request
		return;

	m_logTargets.erase(it);
}

//
// The only two exported functions of the library
//
static CCoreRuntime* g_coreRuntime= NULL;
static boost::mutex g_spcore_mutex;
static bool g_spcore_freed= false;

SPEXPORT_FUNCTION ICoreRuntime* getSpCoreRuntime()
{
	assert (!g_spcore_freed);
	boost::mutex::scoped_lock lock(g_spcore_mutex);

	if (!g_coreRuntime) g_coreRuntime= new CCoreRuntime();
	return g_coreRuntime;
}

SPEXPORT_FUNCTION void freeSpCoreRuntime()
{
//	boost::mutex::scoped_lock lock(g_spcore_mutex);

	if (g_coreRuntime) {
		delete g_coreRuntime;
		g_spcore_freed= true;
		// Invalidate pointer
		g_coreRuntime= NULL;
	}
}


} // namespace spcore
