/**
* @file		coreruntime.h
* @brief	Interface class for lib-sitplus core functions.
* @author	Cesar Mauri Loba (cesar at crea-si dot com)
*	
* -------------------------------------------------------------------------
*
* Copyright:   (C) 2010 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/>.
*/
#ifndef SPCORE_CORERUNTIME_H
#define SPCORE_CORERUNTIME_H

#include "spcore/libimpexp.h"
#include "spcore/baseobj.h"
#include "config.h"		// ENABLE_WXWIDGETS define

/**
One of the goals of SITPLUS is to become GUI toolkit agnostic.
Currently it uses wxWidgets and most modules provide GUI's based on this 
toolkit, but the core itself has not an strong dependency (component's 
method GetGUI expects wxWindows and wxPanel types though this is easyly 
changeable by just defining a neutral window type, the core itself 
provides methods such as InitGUISupport, RunMessageLoop and 
CleanupGUISupport which are based on wx).

@todo provide an interface for non-wx apps and/or other toolkits
and set this define as a build parameter
*/

#ifndef ENABLE_WXWIDGETS
#error "Currently wxWidgets is necessary"
#endif

namespace spcore {

// Forward class declarations
template<class T> class IIterator;
class ITypeFactory;
class CTypeAny;
class IComponentFactory;
class IComponent;
class IModule;
class IInputPin;
class IOutputPin;
class IConfiguration;
class IPaths;
class ILogTarget;

/**
	@brief Interface class for lib-sitplus core functions.

	Call spcore::getSpCoreRuntime() to get the only instance of the class 
	that implements the core interface.
**/
class ICoreRuntime {
public:
	virtual ~ICoreRuntime() {}

	/**
		@brief Get the runtime ID of a named type.
		@param name type name
		@return the ID or TYPE_INVALID if the specified type doesn't exists.
	**/
	virtual int ResolveTypeID(const char * name) = 0;

	/**
		@brief Get all registered types.
		@return an iterator to a collection of type factories.
	**/
	virtual SmartPtr<IIterator<ITypeFactory*> > QueryTypes() = 0;

	/**
		@brief Creates a new instance of certain type given its name.
		@param typeName type name.
		@return pointer to the new instance or NULL if the type doesn't exists 
			or another error occurred.
	**/
	virtual SmartPtr<CTypeAny> CreateTypeInstance(const char * typeName) = 0;

	/**
		@brief Creates a new instance of certain type given its ID.
		@param id type identifier.
		@return pointer to the new instance or NULL if the type doesn't exists 
			or another error occurred.
	**/
	virtual SmartPtr<CTypeAny> CreateTypeInstance(int id) = 0;

	/**
		@brief Get all registered components.
		@return an iterator to a collection of component factories.
	**/
	virtual SmartPtr<IIterator<IComponentFactory*> > QueryComponents() = 0;

	/**
		@brief Create a new instance of a component.
		@param typeName name of the component type.
		@param name name given to the new instance.
		@param argc number of arguments provided in argv array.
		@param argv array of arguments.
		@return smart pointer to the newly created component or NULL when error.

		Creates a new instance of the component of type "typeName" and names it with
		"name". Specific values for argc and argv are component type dependent.
	**/
	virtual SmartPtr<IComponent> CreateComponent(const char * typeName, const char * name, int argc, const char * argv[]) = 0;

	/**
		@brief Create an instance of an output pin.
		@param type name of the type of the pin.
		@param name name given to the pin.
		@param locked if it is true constructs a looked (synchronized) pin.
		@return smart pointer to the new pin or NULL when error.
	**/
	virtual SmartPtr<IOutputPin> CreateOutputPin(const char* type, const char* name, bool locked) = 0;

	/**    
		@brief Register a module inside spcore.
		@param module module instance.
		@return	0 on success,
				-1 : module already registered,
				-2 : wrong core version,
				-3 : type name already registered,
				-4 : component already registered.
    **/
	virtual int RegisterModule(SmartPtr<IModule> module) = 0;

	/**
		@brief Load and register a module.
		@param name name of the shared library to load.
		@param dir path where look for library files. If dir is NULL then
			current working directory and system library paths are searched.
		@return 0 on success,
				-1 : module already registered,
				-2 : wrong core version,
				-3 : type name already registered,
				-4 : component already registered,
				-5 : defective element provided in library (e.g. anonymous factory),
				-6 : library not found,
				-7 : wrong library format (symbol not found),
				-8 : no module.
	**/
	virtual int LoadModule(const char * name, const char * dir = NULL) = 0;

	/**
		@brief Log severity levels.
	*/
	enum LogSeverityLevel { 
		LOG_FATAL= 0,	/**< reserved for special exceptions/conditions when recovery is not possible. */
		LOG_ERROR,		/**< used to log all unhandled exceptions which prevent the application runing properly. */
		LOG_WARNING,	/**< often used for handled 'exceptions' or other important log events. */
		LOG_INFO,		/**< typically used to output information that is useful for the running and 
							management of the system. */
		LOG_DEBUG		/**< is the most verbose logging level. Only for development and testing. */
	};

	/**
		@brief Send a message to the logging subsystem.
		@param severity severity level of the message
		@param message message to log
		@param module module name (deprecated)
	*/
	virtual void LogMessage (LogSeverityLevel severity, const char* message, const char* module= NULL)= 0;

	/**
		@brief Register a new log target.
		@param lt pointer to the log target to register.

		After calling this method all log messages will be (also) sent to the registered target.
		If the target was previously registered the request is ignored silently.
	*/
	virtual void RegisterLogTarget (ILogTarget* lt)= 0;

	/**
		@brief Unregister a log target.
		@param lt pointer to the log target to unregister.
	*/
	virtual void UnregisterLogTarget (ILogTarget* lt)= 0;

	/**
		@brief Construct and return an IConfiguration object.
		@return smart pointer to a new IConfiguration object.
		@todo Remove this method and allow to create IConfiguration instances directly.
	*/
	virtual SmartPtr<IConfiguration> GetConfiguration() const= 0;

	/**
		@brief Get an object to report paths.
		@return reference to the IPath object.
		@todo remove this method and provide a class with static members.
	*/
	virtual IPaths& GetPaths() const= 0;

	/**
		@brief Return whether the caller thread is the main one.
		@todo provide a regular function.
	*/
	virtual bool IsMainThread () const= 0;

#ifdef ENABLE_WXWIDGETS

	/**
		@brief Initializes GUI subsystem (currently only wxWidgets is supported).
		@return 0 on successful initialization or -1 when error

		This method must be called before creating any window or calling RunMessageLoop.
	*/
	virtual int InitGUISupport (int argc, char** argv)= 0;

	/**
		@brief Runs the main message loop.
		@return exit code

		This function does not return until the last frame window has been destroyed 
		as the regular wx message loop does.
	*/
	virtual int RunMessageLoop ()= 0;

	/**
		@brief Finalizes GUI subsystem (wxWidgets currently)

		This method must be called after RunMessageLoop	has exited.
	*/
	virtual void CleanupGUISupport ()= 0;

	/**
		Forwards a message via the application main thread to the destination pin.
		This method waits until the event has been processed.

		\return		0:	message successfully sent
					-1:	type mismatch or message could not be send
		@todo remove this method (ans its implementation).
	*/
	virtual int SendMessageMainThreadSync (SmartPtr<const CTypeAny> msg, IInputPin & dst)= 0;

	/**
		@brief Callback type for SendMessageMainThreadAsync method.		
	*/
	typedef void ToMainThreadCallback (IComponent*, const CTypeAny*);

	/**
		@brief Forwards a message via the application main thread to a callback.

		Some GUI toolkits (such as wx) and other libraries (e.g. SDL) only work 
		properly when its API is called from the main thread. This method allows
		to store a message which the application main thread will collect and 
		deliver through a callback (i.e. asynchronously). Note that, though is 
		possible to send a message synchronously (i.e. waiting until the main 
		thread has delivered the message) this approach could easily cause a 
		deadlock and so is not recommendable.
	*/	
	virtual void SendMessageMainThreadAsync (const CTypeAny&, IComponent&, ToMainThreadCallback*)= 0;

#endif
};

/**
	@brief Interface class for log targets.
*/
class ILogTarget
{
public:
	/**
		@brief Function which will be called each time a log message is received.
		@param severity
		@param message
	*/
	virtual void LogMessage (ICoreRuntime::LogSeverityLevel severity, const char* message)= 0;
};

/**
	@brief Get the ICoreRuntime instance.
	@return pointer to the ICoreRuntime instance.
	The first call to this method will create the appropiate ICoreRuntime implementation instance.
*/
SPEXPORT_FUNCTION 
ICoreRuntime* getSpCoreRuntime();

/**
	@brief Clean up the ICoreRuntime instance.

	Free resources allocated by the ICoreRuntime instance. Should be called just before.
	exiting your host application.
*/
SPEXPORT_FUNCTION 
void freeSpCoreRuntime();

} // namespace spcore
#endif
