#ifndef _MODULETYPE_H_
#define _MODULETYPE_H_

#include "../txmlobject.h"
#include "../ptr.h"

#include "command.h"
#include "imodule.h"
#include "messageclass.h"

#include <vector>
#include <string>

using namespace std;

class ModuleManager;

/// Defines type of module, holds module instances of its type.
class ModuleType:public TObject
{
public:
	typedef vector<Ptr<IModule> > t_instances;
private:
	ModuleManager* manager;
    t_instances instances;
public:
	static Ptr<ModuleType> nullRef;
	
	static const char* type;
	const char* getType() const;

	inline ModuleType():manager(0)
	{
	}

	// -------------------- PURE VIRTUAL METHODS SECTION

	/**
	 * \brief Returns name of module type (such as 'boom').
	 *
	 * Module type name must be unique.
	 *
	 * \todo Check unique names in module manager constructor.
	 *
	 * \return name of module type
	 */
	virtual const string& getName() const=0;
	
	/**
	 * \brief Return array of variables which will module use
	 * \return array of variables.
	 */
	virtual Ptr<VarDef>* getVariables() const=0;

	/** 
     * \brief return module-specific commands
	 */
	virtual Ptr<Command>* getCommands() const=0;

	/**
	 * \brief Create new module instance.
	 *
	 * Typical body of this method is:
	 * \code
	 * {return new Boom();}
	 * \endcode
	 *
	 * \return new module instance
	 */
	virtual IModule* newModule() const=0;

	// --------------END OF PURE VIRTUAL METHODS SECTION

	/**
	 * \brief Register instance of module named instanceName into the system.
	 *
	 * Throws exception if instance of name "instanceName" already exist in the system.
	 *
	 * \param module module to enregister
	 * \param instanceName module instance name
	 */
	void registerModule(IModule* module,const string& instanceName);

	/**
	 * \brief return definition of variable named name or NULL if no such variable definition exist
	 * \param name name of variable
	 * \return variable definition
	 */
	VarDef* getVariable(const string& name);

	/**
	 * \brief return definition of command or NULL if no such command definition exist
	 * \param cmdName name of command
	 * \return variable definition
	 */
	Command* getCommand(const string& cmdName);
	
	/**
	 * \brief return module named instanceName
	 *
	 * Search only in local module instances ie. instances with module type "this".
	 *
	 * \param instanceName name of module instance
	 * \return instance of module
	 */
	Ptr<IModule>& getModule(const string& instanceName);
	
	/**
	 * \brief Same as function getModule()
	 * \param instanceName name of module instance
	 * \return instance of module
	 */
	Ptr<IModule>& operator[](const string& instanceName);
	
	/**
	 * \brief Send message to all local instances.
	 * \param mesg object representing message
	 */
	void sendToAll(TObject* mesg);
	
	/**
	 * \brief test on module name (text comparsion)
	 * \param s another module name
	 * \return true on match
	 */
	inline bool operator==(const string& s) const
	{
		return (s==getName());
	}

	/**
	 * \brief return pointer to module manager 
	 * \return module manager
	 */
	ModuleManager* getManager()
	{
		return manager;
	}

	friend class ModuleManager;
};

#endif/*_MODULETYPE_H_*/
