/*
$Id: NeutronVector.hh 2332 2012-02-16 01:05:03Z jisuzuki $
*/


#ifndef NEUTRONVECTOR_HH
#define NEUTRONVECTOR_HH
#include <boost/serialization/serialization.hpp>

#include "Header.hh"

///////////////////////////////////////////////
//!Data container template.
/*!
This class is a container class.
If you want to put objects,
for example NeutronVector,
into this class, it must be set 1 (default value).

The STL vector is used as a data object storage in this
template, you can add data objects at any time by using
"add( T* )".
When you call the destructor of this class,
Not only the pointer entry in the vector,
but also the substance of the data objects
and header object will be deleted completely.

The example are given in following,
\include NeutronVector.example1.cc
\include NeutronVector.example2.cc
*/

template < class T , class H >
class NeutronVector
{
private:
  void erase();

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

  friend class WriteNeXusFile;
  /** called from WriteNEXusFile::WriteData()
   *
   */
  template <class Write>
  void NXwrite(Write &W) const;

  friend class ReadNeXusFile;
  /** called from ReadNEXusFile::ReadData()
   *
   */
  template <class Read>
  void NXread(Read &R);

protected:
  /** preprocess for the generation of filenames
   *
   */
  template <class Archive>
  std::vector<std::string> presave(Archive &ar, const std::string &masterfile, const unsigned int splitnum) const;

  /** preprocess for the reading header serialization object
   *
   */
  template <class Archive>
  void preload(Archive &ar,
               std::vector<std::string> &S, std::vector<UInt4> &csize);

  template <class Archive>
  friend class WriteSerializationFile;
  //!< to access from WriteSerializationFile::SplitSave() to presave() (parallel save)

  template <class Archive>
  friend class ReadSerializationFile;
  //!< to access from ReadSerializationFile::SplitLoad() to preload() (parallel save)

protected:
  std::vector< T* > v;
  H *header;

public:
  NeutronVector();/*!< @brief Constructor. */
  NeutronVector( H pheader );/*!< @brief Constructor. */
  ~NeutronVector(); /*!< @brief Destructor */
  NeutronVector( const NeutronVector &ob );

  NeutronVector operator=( const NeutronVector &ob );

  void Allocate( UInt4 size );
  /*!< @brief
    All of data stored in this container are deleted,
    and created a new std::vector whose sise is specified by the argument.
  */

  void Set( UInt4 index, T* value );


  UInt4 AddPointer( T* value );
  /*!< @brief "T*" is the each array element pointer.

   Each T is stored into the STL vector object,
   you can use this method at any time.

   CAUTION: stored pointer still be pointing external object
  */

  UInt4 Add( T value );
  /*!< @brief
    "T value" is the data object,
    and each object is copied to a dynamical object.

    The dynamical object will be stored into the container.
    Each T is stored into the STL vector object,
    you can use this method at any time.*/

  UInt4 Add( NeutronVector<T,H>  &value );


  T  Put( UInt4 index=0 );
  T* PutPointer( UInt4 index=0 );

  T* operator()( UInt4 index ) { return PutPointer( index ); }
  /*!< @brief
    Returns the pointer of stored container(ElementContainer for
    ElementContainerArray, ECA for ECM...
    whose index number is "index".
   */

  //! ref() reference implementation of the operator[]
  T &ref(UInt4 index) { return *v[index]; }

  //! ref() reference implementation of the operator[]
  // Put(), PutPointer(), operator() are to be replaced by this method
  const T &ref(UInt4 index) const { return *v[index]; }

  void InputHeader( H pheader );
  /*!< @brief
    input header object.

    If the object have existed already,
    the old one will be deleted.
   */

  H PutHeader();
  H *PutHeaderPointer() const { return header; }
  /*!< @brief Returns the pointer of the header object. */

  void reset(){ erase(); }
  /*!< @brief Reset the data storage in this class.

   Data storage is erased competely.*/
  UInt4 PutTableSize() const { return (UInt4)(v.size()); }
  /*!< @brief alias of getTableSize() */
  UInt4 EraseElement( UInt4 i );
  /*!< @brief Delete the i-th data in the vector,
   the vector size decreases by 1.

   Not only the pointer entry in the vector
   but also the substance of the i-th data object
   will be deleted by this method.
   */

  UInt4 PutSize() const { return PutTableSize(); }
  /*!< @brief alias of PutTableSize() */

  UInt4 ClearElement( UInt4 i );
  /*!< @brief Clear the i-th element in the vector.

   The size of vector is not changed.
   The i-th value in the vector is set as NULL.*/
  UInt4 copy( UInt4 i );
  /*!< @brief Copy and add a T-type object
    from the i-th object
    to the end of the vector-container.

    A return value of this method is the
    number of std::vector size added in this method.*/


  void AddToHeader( std::string Key, Int4   value ){ header->Add( Key, value ); }
  /*!< @brief
    Data objects can be installed into the header-object with
    its name-tag.

    The method of the header-object is executed
    in this method. See the manual of HeaderBase.
   */
  void AddToHeader( std::string Key, Double value ){ header->Add( Key, value ); }
  /*!< @brief
    Data objects can be installed into the header-object with
    its name-tag.

    The method of the header-object is executed
    in this method. See the manual of HeaderBase.
   */
  void AddToHeader( std::string Key, std::string value ){ header->Add( Key, value ); }
  /*!< @brief
    Data objects can be installed into the header-object with
    its name-tag.

    The method of the header-object is executed
    in this method. See the manual of HeaderBase.
   */
  void AddToHeader( std::string Key, std::vector<Int4>   value ){ header->Add( Key, value ); }
  /*!< @brief
    Data objects can be installed into the header-object with
    its name-tag.

    The method of the header-object is executed
    in this method. See the manual of HeaderBase.
   */
  void AddToHeader( std::string Key, std::vector<Double> value ){ header->Add( Key, value ); }
  /*!< @brief
    Data objects can be installed into the header-object with
    its name-tag.

    The method of the header-object is executed
    in this method. See the manual of HeaderBase.
   */
  void AddToHeader( std::string Key, std::vector<std::string> value ){ header->Add( Key, value ); }
  /*!< @brief
    Data objects can be installed into the header-object with
    its name-tag.

    The method of the header-object is executed
    in this method. See the manual of HeaderBase.
   */

  /** performs std::transform() to a vector with specified key and function object
   *
   * @param Key     a key which specifies the target std::vector
   * @param F       a std std::vector of function object (or a vector of std::vector of ... of function object)
   * @param newunit new unit
   */
  template <class Func>
  void Transform(const std::string &Key, std::vector< Func > F, const std::string &newunit="None");

  //! reverse all std::vector
  void Reverse(void) ;

  /** resize its std::vector
   *
   * if newsize is smaller than current size (shrink), objects pointed
   * from std::vector v are remove. new size is larger, new pointers in std::vector
   * point created new objects
   *
   * @param newsize size of std::vector v to become
   */
  void Resize(UInt4 newsize);

  NeutronVector<T, H> & operator+=(const NeutronVector<T, H> &r );
  NeutronVector<T, H> & operator-=(const NeutronVector<T, H> &r );
  NeutronVector<T, H> & operator*=(const NeutronVector<T, H> &r );
  NeutronVector<T, H> & operator/=(const NeutronVector<T, H> &r );

  NeutronVector<T, H> operator+( NeutronVector<T, H> &r );
  NeutronVector<T, H> operator-( NeutronVector<T, H> &r );
  NeutronVector<T, H> operator*( NeutronVector<T, H> &r );
  NeutronVector<T, H> operator/( NeutronVector<T, H> &r );


};
////////////////////////////////////////////////

#include "NeutronVector.cc"

#endif
