/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_STD_VALUE_HPP
#define NMM_STD_VALUE_HPP NMM_STD_VALUE_HPP

#include "nmm/nmm_prefix.hpp"

#include "IValueStream.hpp"
#include "OValueStream.hpp"

#include "nmm/utils/NamedObject.hpp"

#include <string>
#include <list>
#include <vector>
#include <map>

#include "visibility.hpp"

namespace NMM {

  /** Output serialization operator for type std::wstring.
   * This operator writes a value of type std::wstring to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const wstring& value) ;

  /** Input serialization operator for type std::wstring.
   * This operator reads a value of type std::wstring from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, wstring& value) ;

  /** Output serialization operator for type std::string.
   * This operator writes a value of type std::string to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<string>& value) ;

  /** Input serialization operator for type std::string.
   * This operator reads a value of type std::string from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<string>& value) ;

  /** Output serialization operator for type std::list<float>.
   * This operator writes a value of type std::list<float> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<nmm_float>& value) ;

  /** Input serialization operator for type std::list<float>.
   * This operator reads a value of type std::list<float> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<nmm_float>& value) ;

  /** Output serialization operator for type std::list<double>.
   * This operator writes a value of type std::list<double> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<nmm_double>& value) ;

  /** Input serialization operator for type std::list<double>.
   * This operator reads a value of type std::list<double> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<nmm_double>& value) ;

  /** Output serialization operator for type std::list<nmm_uint32>.
   * This operator writes a value of type std::list<nmm_uint32> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<nmm_uint32>& value) ;

  /** Input serialization operator for type std::list<nmm_uint32>.
   * This operator reads a value of type std::list<nmm_uint32> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<nmm_uint32>& value) ;

  /** Output serialization operator for type std::list<nmm_int32>.
   * This operator writes a value of type std::list<nmm_int32> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<nmm_int32>& value) ;

  /** Input serialization operator for type std::list<nmm_int32>.
   * This operator reads a value of type std::list<nmm_int32> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<nmm_int32>& value) ;

  /** Output serialization operator for type std::list<nmm_uint16>.
   * This operator writes a value of type std::list<nmm_uint16> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<nmm_uint16>& value) ;

  /** Input serialization operator for type std::list<nmm_uint16>.
   * This operator reads a value of type std::list<nmm_uint16> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& ov,list<nmm_uint16>& value);

  /** Output serialization operator for type std::list<nmm_int16>.
   * This operator writes a value of type std::list<nmm_int16> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<nmm_int16>& value) ;

  /** Input serialization operator for type std::list<nmm_int16>.
   * This operator reads a value of type std::list<nmm_int16> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<nmm_int16>& value) ;
  
  /** Output serialization operator for type std::pair<nmm_int32, nmm_int32>.
   * This operator writes a value of type std::pair<nmm_int32, nmm_int32> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const pair<nmm_int32, nmm_int32>& value) ;

  /** Input serialization operator for type std::pair<nmm_int32, nmm_int32>.
   * This operator reads a value of type std::pair<nmm_int32, nmm_int32> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, pair<nmm_int32, nmm_int32>& value) ;

 /** Output serialization operator for type std::pair<nmm_uint64, nmm_uint64>.
   * This operator writes a value of type std::pair<nmm_uint64, nmm_uint64> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const pair<nmm_uint64, nmm_uint64>& value) ;

  /** Input serialization operator for type std::pair<nmm_uint64, nmm_uint64>.
   * This operator reads a value of type std::pair<nmm_uint64, nmm_uint64> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, pair<nmm_uint64, nmm_uint64>& value) ;

  /** Output serialization operator for type std::map<string, string>.
   * This operator writes a value of type std::map<string, string> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const map<string, string>& value) ;

  /** Input serialization operator for type std::map<string, string>.
   * This operator reads a value of type std::map<string, string> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, map<string, string>& value) ;
  
  /** Output serialization operator for type std::list<std::pair<string, nmm_int32>>.
   * This operator writes a value of type std::list<std::pair<string, nmm_int32>> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<pair<string, nmm_int32> >& value) ;

  /** Input serialization operator for type std::list<std::pair<string, nmm_int32>>.
   * This operator reads a value of type std::list<std::pair<string, nmm_int32>> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv,list<pair<string, nmm_int32> >& value) ;
  
  /** Output serialization operator for type std::pair<string, nmm_int32>.
   * This operator writes a value of type std::pair<string, nmm_int32> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const pair<string, nmm_int32>& value) ;

  /** Input serialization operator for type std::pair<string, nmm_int32>.
   * This operator reads a value of type std::pair<string, nmm_int32> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, pair<string, nmm_int32>& value) ;
  
  /** Output serialization operator for type std::map<string, nmm_int32>.
   * This operator writes a value of type std::map<string, nmm_int32> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const map<string, nmm_int32>& value) ;

  /** Input serialization operator for type std::map<string, nmm_int32>.
   * This operator reads a value of type std::map<string, nmm_int32> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, map<string, nmm_int32>& value) ;
  
  /** Output serialization operator for type std::vector<nmm_bool>.
   * This operator writes a value of type std::vector<nmm_bool> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const vector<nmm_bool>& value) ;

  /** Input serialization operator for type std::vector<nmm_bool>.
   * This operator reads a value of type std::vector<nmm_bool> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, vector<nmm_bool>& value) ;
  
  /** Output serialization operator for type std::map<nmm_int32, std::list<nmm_int32>>.
   * This operator writes a value of type std::map<nmm_int32, std::list<nmm_int32>> to an output value stream.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @return ov
   */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const map<nmm_int32, list<nmm_int32> >& value) ;

  /** Input serialization operator for type std::map<nmm_int32, std::list<nmm_int32>>.
   * This operator reads a value of type std::map<nmm_int32, std::list<nmm_int32>> from an input value stream.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @return iv
   */
  DLLEXPORT IValueStream& operator>>(IValueStream& iv, map<nmm_int32, list<nmm_int32> > & value);

  /** Output serialization of a list.
   * This is a helper method which writes a list of serializable objects to an output value stream.
   * It is used for implementing serialization operators for lists.
   *
   * Usage:
   * @code
   * OValueStream& operator<<(OValueStream& ov, const list<NodeDescription>& node_description_list) {
   *   return writeList<NodeDescription>(ov, node_description_list, "NodeDescription");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type list<T> generated by this method has type name "list_TNAME"
   * and type namespace "std" where "TNAME" is the type name of T.
   *
   * @param ov An output value stream
   * @param v_list Reference to variable to be serialized
   * @param type_name Type name of element type T
   */
  template <typename T>
  OValueStream& writeList(OValueStream& ov, const list<T>& v_list, const string type_name) {
    typedef typename list<T>::const_iterator ConstIt; //must be declared as a type
    /* Write the TypInfo */
    ov.beginType("list_"+type_name, "std");

    /* Write all elements of the list */
    for (ConstIt it = v_list.begin(); it !=  v_list.end(); ++it)
      ov << *it;

    ov.endType();
    return ov;
  }

  /** Input serialization of a list.
   * This is a helper method which reads a list of serializable objects from an input value stream.
   * It is used for implementing serialization operators for lists.
   *
   * Usage:
   * @code
   * IValueStream& operator>>(IValueStream& ov, list<NodeDescription>& node_description_list) {
   *   return readList<NodeDescription>(ov, node_description_list, "NodeDescription");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type list<T> generated by this method has type name "list_TNAME"
   * and type namespace "std" where "TNAME" is the type name of T.
   *
   * @param iv An input value stream
   * @param v_list Reference to variable to be serialized
   * @param type_name Type name of element type T
   */
  template <class T>
  IValueStream& readList(IValueStream& iv, list<T>& v_list, const string& type_name) {
    /* Begin> Type checking */
    if (iv.getCurrentType() != "list_"+type_name) {
      GLOBAL_ERROR_STREAM("List> Invalid type assignment" << endl);
      GLOBAL_ERROR_STREAM ("List> Current type : " << iv.getCurrentType() << "                Expected type: " << "list_"+type_name << endl);
      GLOBAL_ERROR_STREAM ("List> Current namespace : " << iv.getCurrentNamespace() << "      Expected namespace: " << "std" << endl);

      iv.nextElement();
      return iv;
    }
    /* End< */

    v_list.clear();

    /* Begin> Access internal attributes */
    if (!iv.goDown()) {
      GLOBAL_DEBUG_STREAM("List seems to be empty" << endl);
      iv.nextElement();
      return iv;
    }
    /* End< */

    /* Begin> While the Stream contains elements, read them */
    while(!iv.isEmpty()) {
      T tmp;
      iv >> tmp;
      v_list.push_back(tmp);
    }
    /* End< */

    iv.goUp();

    return iv;
  }

  /** Output serialization of a vector.
   * This is a helper method which writes a vector of serializable objects to an output value stream.
   * It is used for implementing serialization operators for vectors.
   *
   * Usage:
   * @code
   * OValueStream& operator<<(OValueStream& ov, const vector<NodeDescription>& node_description_vector) {
   *   return writeVector<NodeDescription>(ov, node_description_vector, "NodeDescription");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type vector<T> generated by this method has type name "vector_TNAME"
   * and type namespace "std" where "TNAME" is the type name of T.
   *
   * @param ov An output value stream
   * @param v_vector Reference to variable to be serialized
   * @param type_name Type name of element type T
   */
  template <typename T>
  OValueStream& writeVector(OValueStream& ov, const vector<T>& v_vector, const string type_name) {
    typedef typename vector<T>::const_iterator ConstIt; //must be declared as a type
    /* Write the TypInfo */
    ov.beginType("vector_"+type_name, "std");


    /* Write the size */
    ov << static_cast<nmm_uint32>(v_vector.size());

    /* Write all elements of the list */
    for (ConstIt it = v_vector.begin(); it !=  v_vector.end(); ++it)
      ov << *it;

    ov.endType();
    return ov;
  }

  /** Input serialization of a vector.
   * This is a helper method which reads a vector of serializable objects from an input value stream.
   * It is used for implementing serialization operators for vectors.
   *
   * Usage:
   * @code
   * IValueStream& operator>>(IValueStream& ov, vector<NodeDescription>& node_description_vector) {
   *   return readVector<NodeDescription>(ov, node_description_vector, "NodeDescription");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type vector<T> generated by this method has type name "vector_TNAME"
   * and type namespace "std" where "TNAME" is the type name of T.
   *
   * @param iv An input value stream
   * @param v_vector Reference to variable to be serialized
   * @param type_name Type name of element type T
   */
  template <class T>
  IValueStream& readVector(IValueStream& iv, vector<T>& v_vector, const string& type_name) {
    /* Begin> Type checking */
    if (iv.getCurrentType() != "vector_"+type_name) {
      GLOBAL_ERROR_STREAM("List> Invalid type assignment" << endl);
      GLOBAL_ERROR_STREAM ("List> Current type : " << iv.getCurrentType() << "                Expected type: " << "vector_"+type_name << endl);
      GLOBAL_ERROR_STREAM ("List> Current namespace : " << iv.getCurrentNamespace() << "      Expected namespace: " << "std" << endl);

      iv.nextElement();
      return iv;
    }
    /* End< */

    v_vector.clear();

    /* Begin> Access internal attributes */
    if (!iv.goDown()) {
      GLOBAL_DEBUG_STREAM("List seems to be empty" << endl);
      iv.nextElement();
      return iv;
    }
    /* End< */

    nmm_uint32 size;

    /* read the size of the vector */
    iv >> size;

    v_vector.resize(size);

    /* Begin> While the Stream contains elements, read them */
    for (size_t i = 0; i < size; ++i) {
      iv >> v_vector[i];
    }
    /* End< */

    if (!iv.isEmpty()) {
      GLOBAL_ERROR_STREAM("Unhandled elements from vector_" << type_name << " in IValueStream" << endl);
    }

    iv.goUp();

    return iv;
  }


  /** Input serialization of a vector of bools.
   * This is a helper method which reads a vector of bools from an input value stream.
   * It is used for implementing serialization operators for vector<bool>.
   *
   * The type information of a type vector<bool> is "vector_bool"
   * and type namespace "std".
   *
   * @param iv An input value stream
   * @param v_vector Reference to variable to be serialized
   * @param type_name Type name of element type T
   */
  DLLEXPORT IValueStream& readBoolVector(IValueStream& iv, vector<nmm_bool>& v_vector, const string& type_name);


  /** Output serialization of a map.
   * This is a helper method which writes a map of serializable objects to an output value stream.
   * It is used for implementing serialization operators for maps.
   *
   * Usage:
   * @code
   * OValueStream& operator<<(OValueStream& ov, const map<string, int>& string_int_map) {
   *   return writeMap<string, int>(ov, string_int_map, "string", "int");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type map<T,V> generated by this method has type name "map_TNAME1_TNAME2"
   * and type namespace "std", "TNAME1" is the type name of T and "TNAME2" is the type name of V.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @param first_type Type name of first element type
   * @param second_type Type name of first element type
   */
  template< class T, class V >
  OValueStream& writeMap(OValueStream& ov, const map<T, V>& value, const TypeInfo& first_type, const TypeInfo& second_type)
  {
    typedef typename map<T, V>::const_iterator ConstIt; //must be declared as a type

    /* Write the TypeInfo */
    ov.beginType("map_"+first_type.t_name+"_"+second_type.t_name, "std");

    /* Begin> First write the key, then the value */
    for (ConstIt it = value.begin(); it != value.end(); ++it) {
      ov << it->first;
      ov << it->second;
    }
    /* End< */

    ov.endType();

    return ov;
  }

  /** Input serialization of a map.
   * This is a helper method which reads a map of serializable objects frmo an input value stream.
   * It is used for implementing serialization operators for maps.
   *
   * Usage:
   * @code
   * IValueStream& operator>>(IValueStream& iv, map<string, int>& string_int_map) {
   *   return readMap<string, int>(iv, string_int_map, "string", "int");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type map<T,V> generated by this method has type name "map_TNAME1_TNAME2"
   * and type namespace "std", "TNAME1" is the type name of T and "TNAME2" is the type name of V.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @param first_type Type name of first element type
   * @param second_type Type name of first element type
   */
  template< class T, class V >
  IValueStream& readMap(IValueStream& iv, map<T, V>& value, const TypeInfo& first_type, const TypeInfo& second_type)
  {
    /* Begin> Type checking */
    if (iv.getCurrentType() != "map_"+first_type.t_name+"_"+second_type.t_name && iv.getCurrentNamespace() != "std") {
      GLOBAL_ERROR_STREAM("Map> Invalid type assignment" << endl);
      GLOBAL_ERROR_STREAM ("Map> Current type : " << iv.getCurrentType() << "                Expected type: " << "pair_"+first_type.t_name+"_"+second_type.t_name << endl);
      GLOBAL_ERROR_STREAM ("Map> Current namespace : " << iv.getCurrentNamespace() << "      Expected namespace: " << "std" << endl);
      iv.nextElement();
      return iv;
    }
    /* End< */

    value.clear();

    /* Begin> Access internal attributes */
    if (!iv.goDown()) {
      GLOBAL_DEBUG_STREAM("Invalid Map" << endl);
      iv.nextElement();
      return iv;
    }
    /* End< */

    /* Begin> Read the key, then the value */
    while(!iv.isEmpty()) {
      pair<T, V> tmp_pair;
      iv >> tmp_pair.first;
      iv >> tmp_pair.second;
      value.insert(tmp_pair);
    }
    /* End< */

    iv.goUp();

    return iv;
  }

  /** Output serialization of a pair.
   * This is a helper method which writes a pair of serializable objects to an output value stream.
   * It is used for implementing serialization operators for pairs.
   *
   * Usage:
   * @code
   * OValueStream& operator<<(OValueStream& ov, const pair<string, int>& string_int_pair) {
   *   return writePair<string, int>(ov, string_int_pair, "string", "int");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type pair<T,V> generated by this method has type name "pair_TNAME1_TNAME2"
   * and type namespace "std", "TNAME1" is the type name of T and "TNAME2" is the type name of V.
   *
   * @param ov An output value stream
   * @param value Reference to variable to be serialized
   * @param first_type Type name of first element type
   * @param second_type Type name of first element type
   */
  template< class T, class V >
  OValueStream& writePair(OValueStream& ov, const pair<T, V>& value, const string& first_type, const string& second_type) {
    /* Write the TypeInfo */
    ov.beginType("pair_"+first_type+"_"+second_type, "std");
    /* Write the first element */
    ov << value.first;
    /* Write the second elemetn */
    ov << value.second;

    ov.endType();
    return ov;
  }

  /** Input serialization of a pair.
   * This is a helper method which reads a pair of serializable objects frmo an input value stream.
   * It is used for implementing serialization operators for pairs.
   *
   * Usage:
   * @code
   * IValueStream& operator>>(IValueStream& iv, pair<string, int>& string_int_pair) {
   *   return readMap<string, int>(iv, string_int_pair, "string", "int");
   * }
   * @endcode
   *
   * The operator is not implemented as a template because for each type, type information is needed.
   * The type information of a type pair<T,V> generated by this method has type name "pair_TNAME1_TNAME2"
   * and type namespace "std", "TNAME1" is the type name of T and "TNAME2" is the type name of V.
   *
   * @param iv An input value stream
   * @param value Reference to variable to be serialized
   * @param first_type Type name of first element type
   * @param second_type Type name of first element type
   */
  template< class T, class V >
  IValueStream& readPair (IValueStream& iv, pair<T, V>& value, const string& first_type, const string& second_type) {
    /* Begin> Type checking */
    if (iv.getCurrentType() != "pair_"+first_type+"_"+second_type && iv.getCurrentNamespace() != "std") {
      GLOBAL_ERROR_STREAM("Pair> Invalid type assignment" << endl);
      GLOBAL_ERROR_STREAM ("Pair> Current type : " << iv.getCurrentType() << "                Expected type: " << "pair_"+first_type+"_"+second_type << endl);
      GLOBAL_ERROR_STREAM ("Pair> Current namespace : " << iv.getCurrentNamespace() << "      Expected namespace: " << "std" << endl);
      iv.nextElement();
      return iv;
    }
    /* End< */

    /* Begin> Access the internal attributes */
    if (!iv.goDown()) {
      GLOBAL_DEBUG_STREAM("Invalid Pair" << endl);
      iv.nextElement();
      return iv;
    }
    /* End< */

    /* Read the first element */
    iv >> value.first;
    /* Read the second element */
    iv >> value.second;

    iv.goUp();

    return iv;
  }
  
}

#include "nmm/nmm_suffix.hpp"

#endif
