/* -*- C++ -*-
 * src/lemon/maps.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_MAPS_H
#define LEMON_MAPS_H

#include<math.h>

///\file
///\ingroup maps
///\brief Miscellaneous property maps
///
///\todo This file has the same name as the concept file in concept/,
/// and this is not easily detectable in docs...

#include <map>

namespace lemon {

  /// \addtogroup maps
  /// @{

  /// Base class of maps.

  /// Base class of maps.
  /// It provides the necessary <tt>typedef</tt>s required by the map concept.
  template<typename K, typename T>
  class MapBase
  {
  public:
    ///\e
    typedef K Key;
    ///\e
    typedef T Value;
  };

  /// Null map. (a.k.a. DoNothingMap)

  /// If you have to provide a map only for its type definitions,
  /// or if you have to provide a writable map, but
  /// data written to it will sent to <tt>/dev/null</tt>...
  template<typename K, typename T>
  class NullMap : public MapBase<K,T>
  {
  public:

    /// Gives back a default constructed element.
    T operator[](const K&) const { return T(); }
    /// Absorbs the value.
    void set(const K&, const T&) {}
  };


  /// Constant map.

  /// This is a readable map which assigns a specified value to each key.
  /// In other aspects it is equivalent to the \ref NullMap.
  /// \todo set could be used to set the value.
  template<typename K, typename T>
  class ConstMap : public MapBase<K,T>
  {
    T v;
  public:

    /// Default constructor

    /// The value of the map will be uninitialized. 
    /// (More exactly it will be default constructed.)
    ConstMap() {}
    ///\e

    /// \param _v The initial value of the map.
    ///
    ConstMap(const T &_v) : v(_v) {}

    T operator[](const K&) const { return v; }
    void set(const K&, const T&) {}

    template<typename T1>
    struct rebind {
      typedef ConstMap<K,T1> other;
    };

    template<typename T1>
    ConstMap(const ConstMap<K,T1> &, const T &_v) : v(_v) {}
  };

  ///Returns a \ref ConstMap class

  ///This function just returns a \ref ConstMap class.
  ///\relates ConstMap
  template<class V,class K> 
  inline ConstMap<V,K> constMap(const K &k) 
  {
    return ConstMap<V,K>(k);
  }


  //to document later
  template<typename T, T v>
  struct Const { };
  //to document later
  template<typename K, typename V, V v>
  class ConstMap<K, Const<V, v> > : public MapBase<K, V>
  {
  public:
    ConstMap() { }
    V operator[](const K&) const { return v; }
    void set(const K&, const V&) { }
  };

  /// \c std::map wrapper

  /// This is essentially a wrapper for \c std::map. With addition that
  /// you can specify a default value different from \c Value() .
  ///
  /// \todo Provide allocator parameter...
  template <typename K, typename T, typename Compare = std::less<K> >
  class StdMap : public std::map<K,T,Compare> {
    typedef std::map<K,T,Compare> parent;
    T v;
    typedef typename parent::value_type PairType;

  public:
    typedef K Key;
    typedef T Value;
    typedef T& Reference;
    typedef const T& ConstReference;


    StdMap() : v() {}
    /// Constructor with specified default value
    StdMap(const T& _v) : v(_v) {}

    /// \brief Constructs the map from an appropriate std::map.
    ///
    /// \warning Inefficient: copies the content of \c m !
    StdMap(const parent &m) : parent(m) {}
    /// \brief Constructs the map from an appropriate std::map, and explicitly
    /// specifies a default value.
    ///
    /// \warning Inefficient: copies the content of \c m !
    StdMap(const parent &m, const T& _v) : parent(m), v(_v) {}
    
    template<typename T1, typename Comp1>
    StdMap(const StdMap<Key,T1,Comp1> &m, const T &_v) { 
      //FIXME; 
    }

    Reference operator[](const Key &k) {
      return insert(PairType(k,v)).first -> second;
    }
    ConstReference operator[](const Key &k) const {
      typename parent::iterator i = lower_bound(k);
      if (i == parent::end() || parent::key_comp()(k, (*i).first))
	return v;
      return (*i).second;
    }
    void set(const Key &k, const T &t) {
      parent::operator[](k) = t;
    }

    /// Changes the default value of the map.
    /// \return Returns the previous default value.
    ///
    /// \warning The value of some keys (which has already been queried, but
    /// the value has been unchanged from the default) may change!
    T setDefault(const T &_v) { T old=v; v=_v; return old; }

    template<typename T1>
    struct rebind {
      typedef StdMap<Key,T1,Compare> other;
    };
  };

  ///Convert the \c Value of a maps to another type.

  ///This \ref concept::ReadMap "read only map"
  ///converts the \c Value of a maps to type \c T.
  ///Its \c Value is inherited from \c M.
  ///
  ///Actually,
  ///\code
  ///  ConvertMap<X> sh(x,v);
  ///\endcode
  ///it is equivalent with
  ///\code
  ///  ConstMap<X::Key, X::Value> c_tmp(v);
  ///  AddMap<X, ConstMap<X::Key, X::Value> > sh(x,v);
  ///\endcode
  ///\bug wrong documentation
  template<class M, class T> 
  class ConvertMap
  {
    const M &m;
  public:
    typedef typename M::Key Key;
    typedef T Value;

    ///Constructor

    ///Constructor
    ///\param _m is the undelying map
    ///\param _v is the convert value
    ConvertMap(const M &_m) : m(_m) {};
    Value operator[](Key k) const {return m[k];}
  };
  
  ///Returns an \ref ConvertMap class

  ///This function just returns an \ref ConvertMap class.
  ///\relates ConvertMap
  ///\todo The order of the template parameters are changed.
  template<class T, class M>
  inline ConvertMap<M,T> convertMap(const M &m) 
  {
    return ConvertMap<M,T>(m);
  }

  ///Sum of two maps

  ///This \ref concept::ReadMap "read only map" returns the sum of the two
  ///given maps. Its \c Key and \c Value will be inherited from \c M1.
  ///The \c Key and \c Value of M2 must be convertible to those of \c M1.

  template<class M1,class M2> 
  class AddMap
  {
    const M1 &m1;
    const M2 &m2;
  public:
    typedef typename M1::Key Key;
    typedef typename M1::Value Value;

    ///Constructor

    ///\e
    ///
    AddMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {};
    Value operator[](Key k) const {return m1[k]+m2[k];}
  };
  
  ///Returns an \ref AddMap class

  ///This function just returns an \ref AddMap class.
  ///\todo How to call these type of functions?
  ///
  ///\relates AddMap
  ///\todo Wrong scope in Doxygen when \c \\relates is used
  template<class M1,class M2> 
  inline AddMap<M1,M2> addMap(const M1 &m1,const M2 &m2) 
  {
    return AddMap<M1,M2>(m1,m2);
  }

  ///Shift a maps with a constant.

  ///This \ref concept::ReadMap "read only map" returns the sum of the
  ///given map and a constant value.
  ///Its \c Key and \c Value is inherited from \c M.
  ///
  ///Actually,
  ///\code
  ///  ShiftMap<X> sh(x,v);
  ///\endcode
  ///it is equivalent with
  ///\code
  ///  ConstMap<X::Key, X::Value> c_tmp(v);
  ///  AddMap<X, ConstMap<X::Key, X::Value> > sh(x,v);
  ///\endcode
  template<class M> 
  class ShiftMap
  {
    const M &m;
    typename M::Value v;
  public:
    typedef typename M::Key Key;
    typedef typename M::Value Value;

    ///Constructor

    ///Constructor
    ///\param _m is the undelying map
    ///\param _v is the shift value
    ShiftMap(const M &_m,const Value &_v ) : m(_m), v(_v) {};
    Value operator[](Key k) const {return m[k]+v;}
  };
  
  ///Returns an \ref ShiftMap class

  ///This function just returns an \ref ShiftMap class.
  ///\relates ShiftMap
  ///\todo A better name is required.
  template<class M> 
  inline ShiftMap<M> shiftMap(const M &m,const typename M::Value &v) 
  {
    return ShiftMap<M>(m,v);
  }

  ///Difference of two maps

  ///This \ref concept::ReadMap "read only map" returns the difference
  ///of the values returned by the two
  ///given maps. Its \c Key and \c Value will be inherited from \c M1.
  ///The \c Key and \c Value of \c M2 must be convertible to those of \c M1.

  template<class M1,class M2> 
  class SubMap
  {
    const M1 &m1;
    const M2 &m2;
  public:
    typedef typename M1::Key Key;
    typedef typename M1::Value Value;

    ///Constructor

    ///\e
    ///
    SubMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {};
    Value operator[](Key k) const {return m1[k]-m2[k];}
  };
  
  ///Returns a \ref SubMap class

  ///This function just returns a \ref SubMap class.
  ///
  ///\relates SubMap
  template<class M1,class M2> 
  inline SubMap<M1,M2> subMap(const M1 &m1,const M2 &m2) 
  {
    return SubMap<M1,M2>(m1,m2);
  }

  ///Product of two maps

  ///This \ref concept::ReadMap "read only map" returns the product of the
  ///values returned by the two
  ///given
  ///maps. Its \c Key and \c Value will be inherited from \c M1.
  ///The \c Key and \c Value of \c M2 must be convertible to those of \c M1.

  template<class M1,class M2> 
  class MulMap
  {
    const M1 &m1;
    const M2 &m2;
  public:
    typedef typename M1::Key Key;
    typedef typename M1::Value Value;

    ///Constructor

    ///\e
    ///
    MulMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {};
    Value operator[](Key k) const {return m1[k]*m2[k];}
  };
  
  ///Returns a \ref MulMap class

  ///This function just returns a \ref MulMap class.
  ///\relates MulMap
  template<class M1,class M2> 
  inline MulMap<M1,M2> mulMap(const M1 &m1,const M2 &m2) 
  {
    return MulMap<M1,M2>(m1,m2);
  }
 
  ///Scale a maps with a constant.

  ///This \ref concept::ReadMap "read only map" returns the value of the
  ///given map multipied with a constant value.
  ///Its \c Key and \c Value is inherited from \c M.
  ///
  ///Actually,
  ///\code
  ///  ScaleMap<X> sc(x,v);
  ///\endcode
  ///it is equivalent with
  ///\code
  ///  ConstMap<X::Key, X::Value> c_tmp(v);
  ///  MulMap<X, ConstMap<X::Key, X::Value> > sc(x,v);
  ///\endcode
  template<class M> 
  class ScaleMap
  {
    const M &m;
    typename M::Value v;
  public:
    typedef typename M::Key Key;
    typedef typename M::Value Value;

    ///Constructor

    ///Constructor
    ///\param _m is the undelying map
    ///\param _v is the scaling value
    ScaleMap(const M &_m,const Value &_v ) : m(_m), v(_v) {};
    Value operator[](Key k) const {return m[k]*v;}
  };
  
  ///Returns an \ref ScaleMap class

  ///This function just returns an \ref ScaleMap class.
  ///\relates ScaleMap
  ///\todo A better name is required.
  template<class M> 
  inline ScaleMap<M> scaleMap(const M &m,const typename M::Value &v) 
  {
    return ScaleMap<M>(m,v);
  }

  ///Quotient of two maps

  ///This \ref concept::ReadMap "read only map" returns the quotient of the
  ///values returned by the two
  ///given maps. Its \c Key and \c Value will be inherited from \c M1.
  ///The \c Key and \c Value of \c M2 must be convertible to those of \c M1.

  template<class M1,class M2> 
  class DivMap
  {
    const M1 &m1;
    const M2 &m2;
  public:
    typedef typename M1::Key Key;
    typedef typename M1::Value Value;

    ///Constructor

    ///\e
    ///
    DivMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {};
    Value operator[](Key k) const {return m1[k]/m2[k];}
  };
  
  ///Returns a \ref DivMap class

  ///This function just returns a \ref DivMap class.
  ///\relates DivMap
  template<class M1,class M2> 
  inline DivMap<M1,M2> divMap(const M1 &m1,const M2 &m2) 
  {
    return DivMap<M1,M2>(m1,m2);
  }
  
  ///Composition of two maps

  ///This \ref concept::ReadMap "read only map" returns the composition of
  ///two
  ///given maps. That is to say, if \c m1 is of type \c M1 and \c m2 is
  ///of \c M2,
  ///then for
  ///\code
  ///  ComposeMap<M1,M2> cm(m1,m2);
  ///\endcode
  /// <tt>cm[x]</tt> will be equal to <tt>m1[m2[x]]</tt>
  ///
  ///Its \c Key is inherited from \c M2 and its \c Value is from
  ///\c M1.
  ///The \c M2::Value must be convertible to \c M1::Key.
  ///\todo Check the requirements.

  template<class M1,class M2> 
  class ComposeMap
  {
    const M1 &m1;
    const M2 &m2;
  public:
    typedef typename M2::Key Key;
    typedef typename M1::Value Value;

    ///Constructor

    ///\e
    ///
    ComposeMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {};
    Value operator[](Key k) const {return m1[m2[k]];}
  };
  
  ///Returns a \ref ComposeMap class

  ///This function just returns a \ref ComposeMap class.
  ///\relates ComposeMap
  template<class M1,class M2> 
  inline ComposeMap<M1,M2> composeMap(const M1 &m1,const M2 &m2) 
  {
    return ComposeMap<M1,M2>(m1,m2);
  }

  ///Negative value of a map

  ///This \ref concept::ReadMap "read only map" returns the negative
  ///value of the
  ///value returned by the
  ///given map. Its \c Key and \c Value will be inherited from \c M.
  ///The unary \c - operator must be defined for \c Value, of course.

  template<class M> 
  class NegMap
  {
    const M &m;
  public:
    typedef typename M::Key Key;
    typedef typename M::Value Value;

    ///Constructor

    ///\e
    ///
    NegMap(const M &_m) : m(_m) {};
    Value operator[](Key k) const {return -m[k];}
  };
  
  ///Returns a \ref NegMap class

  ///This function just returns a \ref NegMap class.
  ///\relates NegMap
  template<class M> 
  inline NegMap<M> negMap(const M &m) 
  {
    return NegMap<M>(m);
  }


  ///Absolute value of a map

  ///This \ref concept::ReadMap "read only map" returns the absolute value
  ///of the
  ///value returned by the
  ///given map. Its \c Key and \c Value will be inherited
  ///from <tt>M</tt>. <tt>Value</tt>
  ///must be comparable to <tt>0</tt> and the unary <tt>-</tt>
  ///operator must be defined for it, of course.
  ///
  ///\bug We need a unified way to handle the situation below:
  ///\code
  ///  struct _UnConvertible {};
  ///  template<class A> inline A t_abs(A a) {return _UnConvertible();}
  ///  template<> inline int t_abs<>(int n) {return abs(n);}
  ///  template<> inline long int t_abs<>(long int n) {return labs(n);}
  ///  template<> inline long long int t_abs<>(long long int n) {return ::llabs(n);}
  ///  template<> inline float t_abs<>(float n) {return fabsf(n);}
  ///  template<> inline double t_abs<>(double n) {return fabs(n);}
  ///  template<> inline long double t_abs<>(long double n) {return fabsl(n);}
  ///\endcode
  

  template<class M> 
  class AbsMap
  {
    const M &m;
  public:
    typedef typename M::Key Key;
    typedef typename M::Value Value;

    ///Constructor

    ///\e
    ///
    AbsMap(const M &_m) : m(_m) {};
    Value operator[](Key k) const {Value tmp=m[k]; return tmp>=0?tmp:-tmp;}
  };
  
  ///Returns a \ref AbsMap class

  ///This function just returns a \ref AbsMap class.
  ///\relates AbsMap
  template<class M> 
  inline AbsMap<M> absMap(const M &m) 
  {
    return AbsMap<M>(m);
  }

  ///Converts an STL style functor to a a map

  ///This \ref concept::ReadMap "read only map" returns the value
  ///of a
  ///given map.
  ///
  ///Template parameters \c K and \c V will become its
  ///\c Key and \c Value. They must be given explicitely
  ///because a functor does not provide such typedefs.
  ///
  ///Parameter \c F is the type of the used functor.
  

  template<class K,class V,class F> 
  class FunctorMap
  {
    const F &f;
  public:
    typedef K Key;
    typedef V Value;

    ///Constructor

    ///\e
    ///
    FunctorMap(const F &_f) : f(_f) {};
    Value operator[](Key k) const {return f(k);}
  };
  
  ///Returns a \ref FunctorMap class

  ///This function just returns a \ref FunctorMap class.
  ///
  ///The third template parameter isn't necessary to be given.
  ///\relates FunctorMap
  template<class K,class V, class F>
  inline FunctorMap<K,V,F> functorMap(const F &f) 
  {
    return FunctorMap<K,V,F>(f);
  }

  ///Converts a map to an STL style functor

  ///This class Converts a map to an STL style functor.
  ///that is it provides an <tt>operator()</tt> to read its values.
  ///
  ///For the sake of convenience it also works as a ususal map, i.e
  ///<tt>operator[]</tt> and the \c Key and \c Value typedefs also exist.

  template<class M> 
  class MapFunctor
  {
    const M &m;
  public:
    typedef typename M::Key Key;
    typedef typename M::Value Value;

    ///Constructor

    ///\e
    ///
    MapFunctor(const M &_m) : m(_m) {};
    ///Returns a value of the map
    
    ///\e
    ///
    Value operator()(Key k) const {return m[k];}
    ///\e
    ///
    Value operator[](Key k) const {return m[k];}
  };
  
  ///Returns a \ref MapFunctor class

  ///This function just returns a \ref MapFunctor class.
  ///\relates MapFunctor
  template<class M> 
  inline MapFunctor<M> mapFunctor(const M &m) 
  {
    return MapFunctor<M>(m);
  }


  /// @}
  
}


#endif // LEMON_MAPS_H
