/**
* @file		module.h
* @brief	Module related stuff.
* @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_MODULE_H
#define SPCORE_MODULE_H

#include "spcore/coreversion.h"
#include "spcore/basetype.h"
#include "spcore/iterator.h"
#include "spcore/component.h"
#include "include/spcore/baseobj.h"
#include <vector>

namespace spcore {

// Forward declarations
template<class T> class IIterator;
class ITypeFactory;
class IComponentFactory;
class IActivity;

/**
	@brief Interface class for modules.
*/
class IModule : public IBaseObject {
protected:
	/**
		@brief Protected destructor to prevent the use of the delete operator.
	*/
	inline virtual ~IModule() {}

public:
	/**
		@brief Returns the version of spcore this module was build against.
		@todo Check this.
	*/
	virtual int GetCoreVersion() const = 0;

	/**
		@brief Returns the version of this.
		@todo Check this.
	*/
	virtual int GetModuleVersion() const = 0;

	/**
		@brief Return the name of the module.
		@return Pointer to an internally managed string.
	*/
	virtual const char* GetName() const = 0;

	/**
		@brief Gets a human readable description of the module.
		@return Pointer to an internally managed string encoded in UTF-8.
	*/	
	virtual const char* GetDescription() const = 0;

	/**
		@brief Get the names of the types this module provides.
		@return Smart pointer to an iterator (which can be NULL) of type factories.
	*/
	virtual SmartPtr<IIterator<ITypeFactory*> > GetTypeFactories() = 0;

	/**
		@brief Get the names of the components this module provides.
		@return Smart pointer to an iterator (which can be NULL) of component factories.
	*/
	virtual SmartPtr<IIterator<IComponentFactory*> > GetComponentFactories() = 0;
};

/**
	@brief Adapter class to create new IModule conforming classes.
*/
class CModuleAdapter : public IModule {
public:
	virtual ~CModuleAdapter() {
		std::vector<IComponentFactory *>::iterator itcf;
  		for (itcf= m_componentFactories.begin(); itcf!= m_componentFactories.end(); ++itcf)
  			(*itcf)->Release();
  		m_componentFactories.clear();
	  
		std::vector<ITypeFactory *>::iterator ittf;
  		for (ittf= m_typeFactories.begin(); ittf!= m_typeFactories.end(); ++ittf)
  			(*ittf)->Release();
  		m_typeFactories.clear();
	}

	virtual int GetCoreVersion() const { return SPCORE_VERSION; }
	virtual int GetModuleVersion() const { return 1; }
	virtual const char* GetDescription() const { return ""; }
	virtual SmartPtr<IIterator<ITypeFactory*> > GetTypeFactories() {
		return SmartPtr<IIterator<ITypeFactory*> >(
			new CIteratorVector<ITypeFactory*>(m_typeFactories), false);
	}
	virtual SmartPtr<IIterator<IComponentFactory*> > GetComponentFactories() {
		return SmartPtr<IIterator<IComponentFactory*> >(
			new CIteratorVector<IComponentFactory*>(m_componentFactories), false);
	}

protected:
	/**
		@brief Register a type factory to this module.
		@param f Smart pointer to a type factory.
		@return 0 when success
	*/
	int RegisterTypeFactory(SmartPtr<ITypeFactory> f) {
		m_typeFactories.push_back(f.get());
  		f->AddRef();
  		return 0;
	}
	/**
		@brief Register a component factory to this module.
		@param c Smart pointer to a component factory.
		@return 0 when success
	*/
	int RegisterComponentFactory(SmartPtr<IComponentFactory> c) {
		m_componentFactories.push_back(c.get());
  		c->AddRef();
  		return 0;
	}

private:
	std::vector<IComponentFactory *> m_componentFactories;
	std::vector<ITypeFactory *> m_typeFactories;
};

} // namespace spcore
#endif
