/* -*- C++ -*-
 * src/lemon/vector_map.h - Part of LEMON, a generic C++ optimization library
 *
 * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
 * (Egervary Combinatorial Optimization Research Group, EGRES).
 *
 * Permission to use, modify and distribute this software is granted
 * provided that this copyright notice appears in all copies. For
 * precise terms see the accompanying LICENSE file.
 *
 * This software is provided "AS IS" with no warranty of any kind,
 * express or implied, and with no claim as to its suitability for any
 * purpose.
 *
 */

#ifndef LEMON_VECTOR_MAP_H
#define LEMON_VECTOR_MAP_H

#include <vector>
#include <algorithm>

#include <lemon/alteration_notifier.h>

///\ingroup graphmaps
///\file
///\brief Vector based graph maps.

namespace lemon {
  
  /// \addtogroup graphmaps
  /// @{
  
  /// The VectorMap template class is graph map structure what
  /// automatically updates the map when a key is added to or erased from
  /// the map. This map factory uses the allocators to implement 
  /// the container functionality. This map factory
  /// uses the std::vector to implement the container function.
  ///
  /// \param Registry The AlterationNotifier that will notify this map.
  /// \param IdMap The IdMap type of the graph items.
  /// \param Value The value type of the map.
  /// 
  /// \author Balazs Dezso
  	

  template <typename _Graph, 
	    typename _Item,
	    typename _Value>
  class VectorMap : public AlterationNotifier<_Item>::ObserverBase {
  public:
		
    /// The graph type of the map. 
    typedef _Graph Graph;
    /// The key type of the map.
    typedef _Item Key;
    /// The id map type of the map.
    typedef AlterationNotifier<_Item> Registry;
    /// The value type of the map.
    typedef _Value Value;

    /// The map type.
    typedef VectorMap Map;
    /// The base class of the map.
    typedef typename Registry::ObserverBase Parent;

  private:
		
    /// The container type of the map.
    typedef std::vector<Value> Container;	

  public:

    /// The reference type of the map;
    typedef typename Container::reference Reference;
    /// The pointer type of the map;
    typedef typename Container::pointer Pointer;

    /// The const value type of the map.
    typedef const Value ConstValue;
    /// The const reference type of the map;
    typedef typename Container::const_reference ConstReference;
    /// The pointer type of the map;
    typedef typename Container::const_pointer ConstPointer;

    /// Constructor to attach the new map into the registry.

    /// It construates a map and attachs it into the registry.
    /// It adds all the items of the graph to the map.
     
    VectorMap(const Graph& _g) : graph(&_g) {
      attach(_g.getNotifier(_Item()));
      build();
    }

    /// Constructor uses given value to initialize the map. 

    /// It construates a map uses a given value to initialize the map. 
    /// It adds all the items of the graph to the map.
     
    VectorMap(const Graph& _g, const Value& _v) : graph(&_g) { 
      attach(_g.getNotifier(_Item()));
      container.resize(graph->maxId(_Item()) + 1, _v);
    }

    VectorMap(const VectorMap& _copy) : graph(_copy.getGraph()) {
      if (_copy.attached()) {
	attach(*_copy.getRegistry());
	container = _copy.container;
      }
    }

    using Parent::attach;
    using Parent::detach;
    using Parent::attached;

    /** Assign operator to copy a map of the same map type.
     */
    VectorMap& operator=(const VectorMap& copy) {
      if (&copy == this) return *this;
      
      if (graph != copy.graph) {
	if (attached()) {
	  detach();
	}
	if (copy.attached()) {
	  attach(*copy.getRegistry());
	}
      }
      container = copy.container;

      return *this;
    }


    virtual ~VectorMap() {
      if (attached()) {
	detach();
      }
    }

    const Graph* getGraph() const {
      return graph;
    }

    /// The subcript operator.

    /// The subscript operator. The map can be subscripted by the
    /// actual items of the graph. 
     
    Reference operator[](const Key& key) {
      return container[graph->id(key)];
    } 
		
    /// The const subcript operator.

    /// The const subscript operator. The map can be subscripted by the
    /// actual items of the graph. 
     
    ConstReference operator[](const Key& key) const {
      return container[graph->id(key)];
    }


    /// The setter function of the map.

    /// It the same as operator[](key) = value expression.
    ///
     
    void set(const Key& key, const Value& value) {
      (*this)[key] = value;
    }

    /// Adds a new key to the map.
		
    /// It adds a new key to the map. It called by the observer registry
    /// and it overrides the add() member function of the observer base.
     
    void add(const Key& key) {
      int id = graph->id(key);
      if (id >= (int)container.size()) {
	container.resize(id + 1);
      }
    }

    /// Erases a key from the map.
		
    /// Erase a key from the map. It called by the observer registry
    /// and it overrides the erase() member function of the observer base.     
    void erase(const Key&) {}

    /// Buildes the map.
		
    /// It buildes the map. It called by the observer registry
    /// and it overrides the build() member function of the observer base.

    void build() { 
      container.resize(graph->maxId(_Item()) + 1);
    }

    /// Clear the map.

    /// It erase all items from the map. It called by the observer registry
    /// and it overrides the clear() member function of the observer base.     
    void clear() { 
      container.clear();
    }

  private:
		
    Container container;
    const Graph *graph;

  };


  template <typename _Base> 
  class VectorMappableGraphExtender : public _Base {
  public:

    typedef VectorMappableGraphExtender<_Base> Graph;
    typedef _Base Parent;

    typedef typename Parent::Node Node;
    typedef typename Parent::NodeIt NodeIt;
    typedef typename Parent::NodeIdMap NodeIdMap;
    typedef typename Parent::NodeNotifier NodeObserverRegistry;

    typedef typename Parent::Edge Edge;
    typedef typename Parent::EdgeIt EdgeIt;
    typedef typename Parent::EdgeIdMap EdgeIdMap;
    typedef typename Parent::EdgeNotifier EdgeObserverRegistry;

    

    template <typename _Value>
    class NodeMap : public VectorMap<Graph, Node, _Value> {
    public:
      typedef VectorMappableGraphExtender<_Base> Graph;

      typedef typename Graph::Node Node;

      typedef VectorMap<Graph, Node, _Value> Parent;

      //typedef typename Parent::Graph Graph;
      typedef typename Parent::Value Value;

      NodeMap(const Graph& g) 
	: Parent(g) {}
      NodeMap(const Graph& g, const Value& v) 
	: Parent(g, v) {}

    };

    template <typename _Value>
    class EdgeMap : public VectorMap<Graph, Edge, _Value> {
    public:
      typedef VectorMappableGraphExtender<_Base> Graph;

      typedef typename Graph::Edge Edge;

      typedef VectorMap<Graph, Edge, _Value> Parent;

      //typedef typename Parent::Graph Graph;
      typedef typename Parent::Value Value;

      EdgeMap(const Graph& g) 
	: Parent(g) {}
      EdgeMap(const Graph& g, const Value& v) 
	: Parent(g, v) {}

    };
    
  };
  
  /// @}
  
}

#endif
