//
// .NAME:	
//  Factory
//
// .AUTHOR:
//  Gilberto Camara, Baudoin Raoult and Fernando Ii
//
// .SUMMARY:
//  Implements a template for the "factory" pattern.
//
//  The "factory" pattern is a technique for creating new
//  instances of objects which defines an abstract interface,
//  (represented by the "Make" module). The subclasses of
//  factory decide which class to instantiate.
//
//  Each subclass of factory "registers" itself at compile time;
//  therefore, the addition of a new factory requires no change
//  the parent class.
//
// .CLIENTS:
//
//
//
// .RESPONSABILITIES:
//
//
//
//  
// .COLLABORATORS:
//
//
//
// .BASE CLASS:
//
//
// .DERIVED CLASSES:
//  	
//
// .REFERENCES:
//  This technique is described in the article 
//  "A New and Useful Template Technique: 'Traits'", 
//  included in the book "C++ Gems"  
//
#ifndef Factory_H
#define Factory_H

#include "Cached.h"
#include "inc_stl.h"

// Class Device Factory - clones a new Device on Request

// struct GETraits {
//	typedef GraphicEngine Type;
//	typedef MvRequest&    Parameter;
//      static  Cached        FactoryName  ( Parameter );
//      static  Type*         DefaultObject( Parameter );
// }


template <class Trait> 
class Factory 
{
  typedef map<Cached,Factory<Trait>*,less<Cached> > Map;
  
  static Map *map_;
  
  Cached     name_;
  
  virtual typename Trait::Type * Build ( typename Trait::Parameter ) = 0;

public:

// -- Normal Constructor

	Factory (const Cached& decoderName);
	virtual ~Factory();

// -- Virtual Constructor 
        static typename Trait::Type* Make  ( typename Trait::Parameter );
};

// Initialisation of static variable

template <class Trait>
typename Factory<Trait>::Map* Factory<Trait>::map_ = 0;

// Constructor

template<class Trait>
Factory<Trait>::Factory(const Cached& name):
	name_(name)
{
        if ( map_ == 0 )
	  map_ = new typename Factory<Trait>::Map();

	// Put the object in the factory dictionary
	(*map_)[name_] = this;
}

// Destructor

template<class Trait>
Factory<Trait>::~Factory ()
{
	// Remove the object from the factory dictionary
	map_->erase ( name_ );

}

// Virtual Constructor

template <class Trait> 
typename Trait::Type*
Factory <Trait>::Make ( typename Trait::Parameter param )
{

	// Retrieve the name of the factory
	const char* name = Trait::FactoryName ( param );

	// No name ? Clone a default object
	if ( name == 0 ) return Trait::DefaultObject ( param );

	// try to find the name on the factory dictionary
	typename Map::iterator i = map_->find ( name );

	// Not found ?  Clone a default object
	if ( i == map_->end() )
		return Trait::DefaultObject ( param );

	// Create an object, based on the input parameters
	return (*i).second->Build ( param );

}

#endif
