/*
$Id: ElementContainerMatrix.hh 2295 2011-08-10 02:57:13Z jisuzuki $
*/


#ifndef ELEMENTCONTAINERMATRIX
#define ELEMENTCONTAINERMATRIX

#include "Header.hh"
#include "NeutronVector.hh"
#include "ElementContainer.hh"
#include "ElementContainerArray.hh"

//! Data container for a set of ElementContainerArray-s and HeaderBase.
/*!
  This class is inherited from the template class,
  NeutronVector<ElementContainerArray,HeaderBase>.
  This class is a Data-container class for storeing
  a set of ElementContainerArray-s and HeaderBase.
  See the manuals of the template class of NeutronVector<T,H>.
 */

class ElementContainerMatrix
  : public NeutronVector< ElementContainerArray, HeaderBase >
{
public:
  using NeutronVector< ElementContainerArray, HeaderBase >::operator();

  ElementContainerMatrix();
    /*!< @brief Constructor.

    This method only calls
    the constructor of the base class.
   */
  ElementContainerMatrix( HeaderBase pheader );
    /*!< @brief Constructor.

    This method only calls
    the constructor of the base class.
   */

  ElementContainerMatrix( const NeutronVector< ElementContainerArray, HeaderBase > &ob );
  //!< @brief This copy constructor is very important from operators in NeutronVector

  ElementContainer*      operator()( UInt4 Mindex, UInt4 Aindex );
  /*!< @brief Returns the pointer of ElementContainer.

    The pointer of ElementContainer is extracted from
    the object of ElementContainerArray indexed by "Aindex".
    The pointer of ElementContainerArray is extracted from this class
    with "Mindex".
   */
  std::vector<Double>*        operator()( UInt4 Mindex, UInt4 Aindex, UInt4 Cindex );
  /*!< @brief
    Returns the pointer of std::vector<Double> whose index-number is "Key".

    The pointer of std::vector<Double> will be obtained from ElementContainer
    which is extracted with
    ElementContainer* operator(UInt4,UInt4).
   */
  std::vector<Double>*        operator()( UInt4 Mindex, UInt4 Aindex, std::string Key );
  /*!< @brief
    Returns the pointer of std::vector<Double> whose name is "Key".

    The pointer of std::vector<Double> will be obtained from ElementContainer
    which is extracted with
    ElementContainer* operator(UInt4,UInt4).
   */

  ElementContainerMatrix( const ElementContainerMatrix &ob );

  std::vector<UInt4> SaveToBinFile( std::string key, std::string FileName );
  /*!< @brief
    Histogram data stored in this class are saved
    as a file in binary data format.

    Histogram data are extracted from each ElementContainer with "key",
    and the dimension of ElementContainerArray is written in the
    type of std::vector<UInt4> and returned by this method.
    The return value will be used as the second argument of
    ReadBinFile(std::string,std::vector<UInt4>,std::string).
   */
  PyObject *SaveToBinFilePy( std::string key, std::string FileName );
  /*!< @brief
    This method has the same functionality as "SaveToBinFile(std::string,std::string)".

    The return value can be recognized by python-environment directory.
   */

  void ReadBinFile( std::string FileName,
    std::vector<UInt4> dimensions,
    std::string key );
  /*!< @brief
    Histogram data stored by SaveToBinFile(std::string,std::string) is read
    with this method, and rebuild ElementContainerMatrix.

    This method should be called just after constructing this
    class method. The binary data will be stored in each ElementContainer
    with "key".
   */
  void ReadBinFile( std::string FileName, PyObject *dimensions,
    std::string key );
  /*!< @brief
    This method has the same functionality
    as "ReadBinFile(std::string,PyObject*,std::string)".

    The second argument should be the return value of
    "SaveToBinFilePy(std::string,std::string)".
   */

  void AppendErr( std::string Counts, std::string Error, Double ErrorValue=0.0 );
  /*!< @brief
    This method appends a vector<Double> into each object of ElementContainer.

    The first argument is the key-name of neutron-counts, and
    the second is the key-name of its error-value created and appended
    by this method.
    The third argument is passed to the constructor of
    "ElementContainerAppendError", please see the manual of it.
   */

  //! accumulation of all ElementContainers (for S(Q) merging)
  void AllSum(ElementContainer &res) {
    for (UInt4 i=0;i<v.size();++i) {
      for (UInt4 j=0;j<v[i]->v.size();++j) {
        res += *v[i]->v[j];
      }
    }
  }

  ElementContainerMatrix Transpose();
  /*!<
    This method returns a transposed element container matrix.
    If a shape of the element container matrix is not rectangular,
    this method returns non-transposed one.
  */


  ElementContainerMatrix Mul( Double d );
  ElementContainerMatrix &MulMySelf( Double d );
  ElementContainerMatrix Mul( Double d, Double e );
  ElementContainerMatrix &MulMySelf( Double d, Double e );
  ElementContainerMatrix Mul( std::pair<Double,Double> &p ){ return Mul(p.first,p.second); }
  ElementContainerMatrix &MulMySelf( std::pair<Double,Double> &p ){ return MulMySelf(p.first,p.second); }

  ElementContainerMatrix Plus( Double d );
  ElementContainerMatrix &PlusMySelf( Double d );
  ElementContainerMatrix Plus( Double d, Double e );
  ElementContainerMatrix &PlusMySelf( Double d, Double e );
  ElementContainerMatrix Plus( std::pair<Double,Double> &p ){ return Plus(p.first,p.second); }
  ElementContainerMatrix &PlusMySelf( std::pair<Double,Double> &p ){ return PlusMySelf(p.first,p.second); }

  ElementContainerMatrix Pow( Double d );
  ElementContainerMatrix &PowMySelf( Double d );

  ElementContainerMatrix MergeWithWeight( ElementContainerMatrix &ecm );
};


#endif
