//
// .NAME:	
//  Prototype
//
// .AUTHOR:
//  Gilberto Camara, Baudoin Raoult and Fernando Ii
//
// .SUMMARY:
//  Implements a template for the "prototype" pattern.
//
//  The "prototype" pattern is an extension of the "singleton"
//  pattern, for a hierarchy of classes which is instantiated
//  at runtime.
//
//  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 Prototype_H
#define Prototype_H

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

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

// struct BuilderTraits {
//	typedef Builder       Type;
//      static  Type&         DefaultObject();
// }


template <class Trait> 
class Prototype 
{

	typedef map<Cached, typename Trait::Type*, less<Cached> > Map;

	static Map *map_;

        Cached     name_;

public:

        // -- Normal Constructor
        Prototype (const Cached& prototypeName, typename Trait::Type* proto);
	// -- Destructor
	virtual ~Prototype();

        // -- Virtual Constructor 
        static typename Trait::Type& Find    ( const char* );
        static typename Trait::Type* Lookup  ( const char* );

	const Cached& Name() const { return name_; }
};

// Initialisation of static variable

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

// Constructor

template<class Trait>
Prototype<Trait>::Prototype(const Cached& name, typename Trait::Type* proto):
	name_(name)
{
           if ( map_ == 0 )
	  map_ = new typename Prototype<Trait>::Map();
 
	(*map_)[name_] = proto;
}

// Destructor
template<class Trait>
Prototype<Trait>::~Prototype ()
{
	map_->erase ( name_ );
}

// Virtual Constructor

template <class Trait> 
typename Trait::Type&
Prototype <Trait>::Find ( const char* subclassName )
{

	if ( subclassName == 0 ) return Trait::DefaultObject();

	typename Map::iterator i = map_->find ( subclassName );

	if ( i == map_->end() )
		return Trait::DefaultObject();

	typename Trait::Type* proto = (*i).second;

	return *proto;
}

template <class Trait> 
typename Trait::Type*
Prototype <Trait>::Lookup ( const char* subclassName )
{

	if ( subclassName == 0 ) return Trait::DefaultObject();

	typename Map::iterator i = map_->find ( subclassName );

	if ( i == map_->end() )
		return Trait::DefaultObject();

	typename Trait::Type* proto = (*i).second;

	return proto;
}


#endif
