#ifndef MAP_REGISTRY_H
#define MAP_REGISTRY_H

#include <vector>

using namespace std;

namespace lemon {

/** 
 * Registry class to register edge or node maps into the graph. The
 * registry helps you to implement an observer pattern. If you add
 * or erase an edge or node you must notify all the maps about the
 * event.
*/
  template <typename G, typename K, typename KIt>
  class MapRegistry {
  public:
    typedef G Graph;
    typedef K Key;
    typedef KIt KeyIt;
	


    /**
     * MapBase is the base class of the registered maps.
     * It defines the core modification operations on the maps and
     * implements some helper functions. 
     */
    class MapBase {
    public:
      typedef G Graph;
      typedef MapRegistry<G, K, KIt> Registry;
      typedef K Key;
      typedef KIt KeyIt;
	
      friend class Registry;

      /**
       * Default constructor for MapBase.
       */

      MapBase() : graph(0), registry(0) {}
		
      /** 
       * Simple constructor to register into a graph registry.
      */
	
      MapBase(const Graph& g, Registry& r) : graph(&g), registry(0) {
	r.attach(*this);
      }

      /** 
       * Copy constructor to register into the registry.
      */	
	
      MapBase(const MapBase& copy) : registry(0), graph(copy.graph) {
	if (copy.registry) {
	  copy.registry->attach(*this);
	}
      } 
	
      /** 
       * Assign operator.
      */	

      const MapBase& operator=(const MapBase& copy) {
	if (registry) {
	  registry->detach(*this);
	}
	graph = copy.graph;
	if (copy.registry) {
	  copy.registry->attach(*this);
	}
      }
	

      /** 
       * Destructor. 
      */		

      virtual ~MapBase() {
	if (registry) {
	  registry->detach(*this);
	}
      }

      /*
       * Returns the graph that the map belongs to.
      */

      const Graph* getGraph() const { return graph; }
	
    protected:
		
      const Graph* graph;     
      Registry* registry;

      int registry_index;

    protected:
	
      /**
	 Helper function to implement constructors in the subclasses.
      */
	
      virtual void init() {
	for (KeyIt it(*graph); graph->valid(it); graph->next(it)) {
	  add(it);
	}
      }
	
      /**
	 Helper function to implement the destructor in the subclasses.
      */
	
      virtual void destroy() {
	for (KeyIt it(*getGraph()); getGraph()->valid(it); getGraph()->next(it)) {
	  erase(it);
	}
      }
	
      /** 
	  The add member function should be overloaded in the subclasses.
	  \e Add extends the map with the new node.
      */
	
      virtual void add(const Key&) = 0;	
      /** 
	  The erase member function should be overloaded in the subclasses.
	  \e Erase removes the node from the map.
      */
	
      virtual void erase(const Key&) = 0;
	
      /**
	 Exception class to throw at unsupported operation.
      */
	
      class NotSupportedOperationException {};

    };
	
  protected:
	
    /** 
     * The container type of the maps.
     */
    typedef std::vector<MapBase*> Container; 

    /**
     * The container of the registered maps.
     */
    Container container;

		
  public:
	
    /**
     * Default Constructor of the MapRegistry. It creates an empty registry.
     */
    MapRegistry() {}
	
    /**
     * Copy Constructor of the MapRegistry. The new registry does not steal
     * the maps from the right value. The new registry will be an empty.
     */
    MapRegistry(const MapRegistry&) {}
		
    /**
     * Assign operator. The left value does not steal the maps 
     * from the right value. The left value will be an empty registry.
     */
    MapRegistry& operator=(const MapRegistry&) {
      for (it = container.begin(); it != container.end(); ++it) {
	(*it)->destroy();
	(*it)->graph = 0;
	(*it)->registry = 0;
      }
    }
				
    /**
     * Destructor of the MapRegistry.
     */
    ~MapRegistry() {
      typename Container::iterator it;
      for (it = container.begin(); it != container.end(); ++it) {
	(*it)->destroy();
	(*it)->registry = 0;
	(*it)->graph = 0;
      }
    }
	
	
    public:
	
    /**
     * Attach a map into thr registry. If the map has been attached
     * into an other registry it is detached from that automaticly.
     */
    void attach(MapBase& map) {
      if (map.registry) {
	map.registry->detach(map);
      }
      container.push_back(&map);
      map.registry = this;
      map.registry_index = container.size()-1;
    } 
	
    /**
     * Detach the map from the registry.
     */
    void detach(MapBase& map) {
      container.back()->registry_index = map.registry_index; 
      container[map.registry_index] = container.back();
      container.pop_back();
      map.registry = 0;
      map.graph = 0;
    }
	
		
    /**
     * Notify all the registered maps about a Key added.
     */
    virtual void add(Key& key) {
      typename Container::iterator it;
      for (it = container.begin(); it != container.end(); ++it) {
	(*it)->add(key);
      }
    }	
		
    /**
     * Notify all the registered maps about a Key erased.
     */ 
    virtual void erase(Key& key) {
      typename Container::iterator it;
      for (it = container.begin(); it != container.end(); ++it) {
	(*it)->erase(key);
      }
    }

  };

}

#endif
