/* -*- C++ -*-
 * src/lemon/default_map.h - Part of LEMON, a generic C++ optimization library
 *
 * Copyright (C) 2005 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_DEFAULT_MAP_H
#define LEMON_DEFAULT_MAP_H


#include <lemon/array_map.h>
#include <lemon/vector_map.h>

///\ingroup graphmaps
///\file
///\brief Graph maps that construct and destruct
///their elements dynamically.

namespace lemon {

/// \addtogroup graphmaps
/// @{

  /** The ArrayMap template class is graph map structure what
   *  automatically updates the map when a key is added to or erased from
   *  the map. This map uses the VectorMap if the Value is a primitive
   *  type and the ArrayMap for the other cases.
   *
   *  The template parameter is the MapRegistry that the maps
   *  will belong to and the Value.
   */



  template <typename _Graph, typename _Item, typename _ItemIt, typename _Value>
  struct DefaultMapSelector {
    typedef ArrayMap<_Graph, _Item, _ItemIt, _Value> Map;
  };

  // bool
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, bool> {
    typedef VectorMap<_Graph, _Item, bool> Map;
  };

  // char
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, char> {
    typedef VectorMap<_Graph, _Item, char> Map;
  };

  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, signed char> {
    typedef VectorMap<_Graph, _Item, signed char> Map;
  };

  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, unsigned char> {
    typedef VectorMap<_Graph, _Item, unsigned char> Map;
  };


  // int
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, signed int> {
    typedef VectorMap<_Graph, _Item, signed int> Map;
  };

  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, unsigned int> {
    typedef VectorMap<_Graph, _Item, unsigned int> Map;
  };


  // short
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, signed short> {
    typedef VectorMap<_Graph, _Item, signed short> Map;
  };

  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, unsigned short> {
    typedef VectorMap<_Graph, _Item, unsigned short> Map;
  };


  // long
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, signed long> {
    typedef VectorMap<_Graph, _Item, signed long> Map;
  };

  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, unsigned long> {
    typedef VectorMap<_Graph, _Item, unsigned long> Map;
  };

  // \todo handling long long type


  // float
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, float> {
    typedef VectorMap<_Graph, _Item, float> Map;
  };


  // double
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, double> {
    typedef VectorMap<_Graph, _Item,  double> Map;
  };


  // long double
  template <typename _Graph, typename _Item, typename _ItemIt>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, long double> {
    typedef VectorMap<_Graph, _Item, long double> Map;
  };


  // pointer
  template <typename _Graph, typename _Item, typename _ItemIt, typename _Ptr>
  struct DefaultMapSelector<_Graph, _Item, _ItemIt, _Ptr*> {
    typedef VectorMap<_Graph, _Item, _Ptr*> Map;
  };



  template <typename _Graph, 
	    typename _Item,
	    typename _ItemIt,
	    typename _Value>
  class DefaultMap : public DefaultMapSelector<_Graph, _Item, _ItemIt, _Value>::Map {
  public:
    typedef typename DefaultMapSelector<_Graph, _Item, _ItemIt, _Value>::Map Parent;
    typedef DefaultMap<_Graph, _Item, _ItemIt, _Value> Map;
    
    typedef typename Parent::Graph Graph;
    typedef typename Parent::Value Value;

    DefaultMap(const Graph& _g) : Parent(_g) {}
    DefaultMap(const Graph& _g, const Value& _v) : Parent(_g, _v) {}
  };



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

    typedef DefaultMappableGraphExtender<_Base> Graph;
    typedef _Base Parent;

    typedef typename Parent::Node Node;
    typedef typename Parent::NodeIt NodeIt;

    typedef typename Parent::Edge Edge;
    typedef typename Parent::EdgeIt EdgeIt;

    
    template <typename _Value>
    class NodeMap : public DefaultMap<Graph, Node, NodeIt, _Value> {
    public:
      typedef DefaultMappableGraphExtender Graph;
      typedef DefaultMap<Graph, Node, NodeIt, _Value> Parent;

      NodeMap(const Graph& _g) 
	: Parent(_g) {}
      NodeMap(const Graph& _g, const _Value& _v) 
	: Parent(_g, _v) {}
    };

    template <typename _Value>
    class EdgeMap : public DefaultMap<Graph, Edge, EdgeIt, _Value> {
    public:
      typedef DefaultMappableGraphExtender Graph;
      typedef DefaultMap<Graph, Edge, EdgeIt, _Value> Parent;

      EdgeMap(const Graph& _g) 
	: Parent(_g) {}
      EdgeMap(const Graph& _g, const _Value& _v) 
	: Parent(_g, _v) {}
    };
    
  };

  template <typename _Base> 
  class MappableUndirGraphExtender : 
    public DefaultMappableGraphExtender<_Base> {
  public:

    typedef MappableUndirGraphExtender Graph;
    typedef DefaultMappableGraphExtender<_Base> Parent;

    typedef typename Parent::UndirEdge UndirEdge;
    typedef typename Parent::UndirEdgeIt UndirEdgeIt;

    template <typename _Value>
    class UndirEdgeMap :
      public DefaultMap<Graph, UndirEdge, UndirEdgeIt, _Value> {
    public:
      typedef MappableUndirGraphExtender Graph;
      typedef DefaultMap<Graph, UndirEdge, UndirEdgeIt, _Value> Parent;

      UndirEdgeMap(const Graph& _g) 
	: Parent(_g) {}
      UndirEdgeMap(const Graph& _g, const _Value& _v) 
	: Parent(_g, _v) {}
    };


  };

}

#endif
