/*
$Id: Map.hh 2249 2011-04-28 04:51:48Z jisuzuki $
*/


#ifndef MAP_HH
#define MAP_HH

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>

#include "Header.hh"
////////////////////////////////////////////////

//!General container like STL Map
/*!This class is a general container class like
  STL-std::map.
  Because the STL-std::map applied to template classes
  cannot be used with the swig, this class will be
  utilized instead of the STL-std::map.

  If this class is used from the Python environment,
  you should use concrete class names,
  MapInt4, MapDoubleVector, etc.
  These definitions are written in "analysis/Template.i"
  which is the interface file of SWIG.

  The type of T can be set as not only int, double....
  but also various pointers, *std::vector<Double>
  and class objects. Any objects can be stored
  in this class object.

  This class is not include a copy constructor.
  If you want to copy the class object of this class,
  you should copy each element in your application.
 */

template< class T >
class Map
{
private:
  std::vector< std::string > *KeyVector;
  std::vector< T >      *ValueVector;

  friend class boost::serialization::access;
  /** serialize method used from boost::serialization::access
   *
   */
  template <class Archive>
  void serialize(Archive &ar, const unsigned int ver);

protected:
  Int4 _Check( std::string Key ) const;
  /*!< @brief used in Check() and PutIndexNumber()
   @return -1: non existing; n(>=0): index number */
  void _Add( std::string key, T value );
  /*!< @brief Add() without checking key */

public:
  Map();
  /*!< @brief Constructor. */
 ~Map();
  /*!< @brief Destructor. */
  Map(const Map<T> &ob);
  /*!< @brief copy constructor */
  Map<T> operator=( const Map<T> &ob );

  bool Empty() { return KeyVector->empty(); }
  /*!< @brief Returns empty or no */

  UInt4 Size() const;
  /*!< @brief Returns the size of std::vector. */
  UInt4 PutTableSize() const { return Size(); }
  /*!< @brief Alias of Size(). */

  UInt4 PutIndexNumber( std::string key );
  /*!< @brief Returns "IndexNumber" assigned to "key".*/

  void Add( std::string key, T value );
  /*!< @brief Input a std::pair of information.

   The first argument is a key-word whose type is string.
   The second argument is a value whose type is T.
   This class checks the name of "key" not to register
   doubly. If the installing key name is already installed
   in the storage, you will receive an warning message
   and this addition procedure will be rejected.
  */

  T Find( std::string key );
  /*!< @brief Returns an data element whose name is "key". */
  T Put(  std::string key ){ return Find( key ); }
  /*!< @brief Returns an data element whose name is "key".
   This is an alias of "Find(std::string)".*/

  T Put( UInt4 index ){ return ( *ValueVector )[index]; }
  std::string PutKey( UInt4 index ){ return (*KeyVector)[index]; }


  const T& operator[]( const std::string &key) const;
  /*!< @brief returns a const reference to content (key must be exist) */
  T& operator[]( const std::string &key) ;
  /*!< @brief returns a reference to content
    if key does not exist, new content is added */

  void Clear();
  /*!< @brief Delete all information stored in this class. */

  void Remove( UInt4 IndexNumber );
  /*!< @brief Remove a data element whose index number
   is "IndexNumber".*/
  void Remove( std::string key );
  /*!< @brief Remove a data element whose name is "key". */

  void Dump();
  /*!< @brief Dump all information to standard-output with
   index numbers and keys.

   If the type of T is pointer,
   the address of the pointer will be displayed.*/

  UInt4 Check( std::string Key );
  /*!< @brief Check the existence of the "Key" included in this storage.

    If the "Key" is in this storage, returns 1.
    If the "Key" is not found in it, returns 0.
  */

  friend class HeaderBase;
};
////////////////////////////////////////////////
#include "Map.cc"
/*
 *
 * Map<T> does not have NXwrite and NXread, because HeaderBase writes and reads
 * them directly
 */
#endif
