/*
$Id: ManyoDataIO.cc 291 2016-09-08 07:24:59Z jisuzuki $
 */

#include "ManyoDataIO.hh"
////////////////////////////////////////////////////
ManyoDataIO::ManyoDataIO(){
  H5Eset_auto(H5E_DEFAULT, NULL, NULL); // To mute hdf5 error
  st = new StringTools();
  _status=true;
}
ManyoDataIO::~ManyoDataIO(){
  delete st;
}
////////////////////////////////////////////////////
template <typename T> std::string ManyoDataIO:: tostr(const T& t)
{
    std::ostringstream os; os<<t;
    return os.str();
}

//////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
void ManyoDataIO::
IncertAttribute( hid_t CurrentDir, const std::string &AttributeName, const std::string &AttributeValue ){
  hsize_t NameDims[1];
  NameDims[0] = 1;
  hid_t spaceID_name = H5Screate_simple( 1, NameDims, NULL );
  hid_t atype = H5Tcopy( H5T_C_S1 );
  H5Tset_size( atype, AttributeValue.size() );
  hid_t attributeID = H5Acreate( CurrentDir, AttributeName.c_str(), atype,
                                 spaceID_name, H5P_DEFAULT, H5P_DEFAULT );
  H5Awrite( attributeID, atype, AttributeValue.c_str() );
  H5Aclose( attributeID );
  H5Tclose( atype );
  H5Sclose( spaceID_name );
}
//////////////////////////////////////////////////////////
hid_t ManyoDataIO::
CreateNewFile( const std::string &FileName, const std::string &UserName ){
  hid_t fileID = H5Fcreate( FileName.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
  IncertAttribute( fileID, "user_name", UserName );
  return fileID;
}
hid_t ManyoDataIO::
CreateNewFile( const std::string &FileName, const std::string &UserName, const std::string &version ){
  hid_t fileID = H5Fcreate( FileName.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
  IncertAttribute( fileID, "user_name", UserName );
  Write( version, fileID, "version" );
  return fileID;
}
//////////////////////////////////////////////////////////
hid_t ManyoDataIO::
PrepareNeXus( hid_t CurrentID ){
  hid_t gid = H5Gcreate2( CurrentID, "Entry1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
  IncertAttribute( gid, "NX_class", "NXentry" );
  return gid;
}
//////////////////////////////////////////////////////////
hid_t ManyoDataIO::
MakeNewDataGroup( hid_t CurrentDir, const std::string &GroupName ){
  hid_t gid = H5Gcreate2( CurrentDir, GroupName.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
  IncertAttribute( gid, "NX_class", "NXdata" );
  return gid;
}
//////////////////////////////////////////////////////////
/*
void ManyoDataIO::
Write( ElementContainer *C, const std::string &FileName,
       const std::string &UserName ){

  hid_t fileID = CreateNewFile( FileName, UserName, "2016" );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  Write( C, groupID, "ElementContainerData" );

  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );

}
*/
//////////////////////////////////////////////////////////
/*
void ManyoDataIO::
Write( ElementContainer *C,
       hid_t CurrentGID, const std::string &DataName ){

  hid_t gid;

  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "ElementContainer" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }

  UInt4 size = C->PutSize();

  Write( size, gid, "size" );
  Write( C->PutMergedKey(), gid, "KeyList" );
  for( UInt4 i=0; i<size; i++ ){
    Write( C->PutP( C->PutName(i) ), gid, C->PutName(i) );
  }
  Write( C->PutXKey(), gid, "Xkey" );
  Write( C->PutYKey(), gid, "Ykey" );
  Write( C->PutEKey(), gid, "Ekey" );

  Write( C -> PutHeaderPointer(),     gid, "HeaderBase_in_ElementContainer" );
  Write( C -> PutUnitHeaderPointer(), gid, "UnitHeader_in_ElementContainer" );

  H5Gclose( gid );
}
*/
void ManyoDataIO::
WriteStr( ElementContainer *C,
          hid_t CurrentGID, const std::string &DataName ){

  hid_t gid;

  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "ElementContainer" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }

  UInt4 size = C->PutSize();
  //Write( size, gid, "size" );
  Write( C->PutMergedKey(), gid, "KeyList" );
  for( UInt4 i=0; i<size; i++ ){
    Write( C->PutP( C->PutName(i) ), gid, C->PutName(i) );
  }
  Write( C->PutXKey(), gid, "Xkey" );
  Write( C->PutYKey(), gid, "Ykey" );
  Write( C->PutEKey(), gid, "Ekey" );

  Write( C -> PutHeaderPointer()->DumpToString(),     gid, "HeaderBase_in_ElementContainer" );
  Write( C -> PutUnitHeaderPointer()->DumpToString(), gid, "UnitHeader_in_ElementContainer" );

  H5Gclose( gid );
}


void  ManyoDataIO::Write( ElementContainer *E, const std::string &FileName,
                          const std::string &UserName ){

  hid_t fileID = CreateNewFile( FileName, UserName, "2016" );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  WriteStr( E, groupID, "ElementContainerData" );

  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );
}
//////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
/*
void  ManyoDataIO::Write( ElementContainerArray *A, const std::string &FileName,
                          const std::string &UserName ){

  hid_t fileID = CreateNewFile( FileName, UserName, "2016" );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  Write( A, groupID, "ElementContainerArrayData" );

  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );

}
*/
/*
void  ManyoDataIO::Write( ElementContainerArray *A,
                          hid_t CurrentGID, const std::string &DataName ){
  hid_t gid;
  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "ElementContainerArray" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }
  UInt4 size = A->PutSize();
  Write( size, gid, "size" );
  for( UInt4 i=0; i<size; i++ ){
    std::string name = "ElementContainer" + tostr( i );
    Write( A->PutPointer(i), gid, name.c_str() );
  }
  Write( A -> PutHeaderPointer(), gid, "HeaderBase_in_ElementContainerArray");
  H5Gclose( gid );
}
*/
void  ManyoDataIO::WriteStr( ElementContainerArray *A,
                             hid_t CurrentGID, const std::string &DataName ){
  hid_t gid;
  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "ElementContainerArray" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }
  UInt4 size = A->PutSize();
  Write( size, gid, "size" );
  for( UInt4 i=0; i<size; i++ ){
    std::string name = "ElementContainer" + tostr( i );
    WriteStr( A->PutPointer(i), gid, name.c_str() );
  }
  Write( A -> PutHeaderPointer()->DumpToString(), gid, "HeaderBase_in_ElementContainerArray");
  H5Gclose( gid );
}
void  ManyoDataIO::Write( ElementContainerArray *A, const std::string &FileName,
                          const std::string &UserName ){

  hid_t fileID = CreateNewFile( FileName, UserName, "2016" );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  WriteStr( A, groupID, "ElementContainerArrayData" );

  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );
}

//////////////////////////
/*
void  ManyoDataIO::Write( ElementContainerMatrix *M, const std::string &FileName,
                          const std::string &UserName ){
  hid_t fileID = CreateNewFile( FileName, UserName, "2016" );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  Write( M, groupID, "ElementContainerMatrixData" );

  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );
}
void  ManyoDataIO::Write( ElementContainerMatrix *M,
                          hid_t CurrentGID, const std::string &DataName ){
  hid_t gid;
  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "ElementContainerMatrix" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }
  UInt4 size = M->PutSize();
  Write( size, gid, "size" );
  for( UInt4 i=0; i<size; i++ ){
    std::string name = "ElementContainerArray" + tostr( i );
    Write( M->PutPointer(i), gid, name.c_str() );
  }
  Write( M -> PutHeaderPointer(), gid, "HeaderBase_in_ElementContainerMatrix");
  H5Gclose( gid );
}
*/

void  ManyoDataIO::Write( ElementContainerMatrix *M, const std::string &FileName,
                          const std::string &UserName ){

  hid_t fileID = CreateNewFile( FileName, UserName, "2016" );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  WriteStr( M, groupID, "ElementContainerMatrixData" );

  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );
}
void  ManyoDataIO::WriteStr( ElementContainerMatrix *M,
                             hid_t CurrentGID, const std::string &DataName ){
  hid_t gid;
  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "ElementContainerMatrix" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }
  UInt4 size = M->PutSize();
  Write( size, gid, "size" );
  for( UInt4 i=0; i<size; i++ ){
    std::string name = "ElementContainerArray" + tostr( i );
    WriteStr( M->PutPointer(i), gid, name.c_str() );
  }
  Write( M -> PutHeaderPointer()->DumpToString(), gid, "HeaderBase_in_ElementContainerMatrix");
  H5Gclose( gid );
}
//////////////////////////////////////////////////////////
/*
void ManyoDataIO::
WriteM( ElementContainerMatrix *M, const std::string &FileName,
        const std::string &UserName ){

  hid_t fileID =  CreateNewFile( FileName, UserName );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  hid_t gid = MakeNewDataGroup( groupID, "ElementContainerMatrixData" );

  UInt4 Msize = M->PutSize();
  for( UInt4 i=0; i<Msize; i++ ){
    ElementContainerArray *targetA = M->PutPointer( i );
    UInt4 Asize = targetA -> PutSize();

    hid_t gida = MakeNewDataGroup( gid, "ElementContainerArrayData." + tostr(i) );

    for( UInt4 j=0; j<Asize; j++ ){
      ElementContainer *targetE = targetA -> PutPointer( j );
      std::vector< std::string > keys = targetE -> PutKeys();
      UInt4 Esize = targetE -> PutSize();


      hid_t gide = MakeNewDataGroup( gida, "ElementContainerData." + tostr(j) );


      for( UInt4 k=0; k<Esize; k++ ){
        std::vector< Double > *v = targetE -> PutP( keys[k] );
        //Write( v, gid, std::string( "vec." ) + tostr(i) + "." + tostr(j) + "." + keys[k] );
        Write( v, gide, std::string( "vec." ) + tostr(i) + "." + tostr(j) + "." + keys[k] );
        //Write( v, gide, keys[k] );
      }

      //Write( targetE -> PutHeaderPointer(), gid, std::string("HeaderBase.") + tostr(i) + "." + tostr(j) );
      // これが遅い

      //Write( targetE -> PutHeaderPointer()->DumpToString(), gid, std::string("HeaderBase.") + tostr(i) + "." + tostr(j) );
      // この形式にしても、少ししか速くならない DumpToString()の処理が時間が掛かる？？

      //std::string s = "aaaaaaaaaaaaaaaaaaaaaa";
      //std::cout << targetE -> PutHeaderPointer()->DumpToString() << std::endl;
      Write( "aaaaaaaaaaaaaaaaaaaaaaaa", gid, std::string("HeaderBase.") + tostr(i) + "." + tostr(j) );


      H5Gclose( gide );
    }
    H5Gclose( gida );
  }

  H5Gclose( gid );
  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );

}
*/
//////////////////////////////////////////////////////////
void ManyoDataIO::
Write( HeaderBase *Header,
       hid_t CurrentGID, const std::string &DataName ){

  hid_t gid;

  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "HeaderBase" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }


  std::vector<UInt4> MapList(6);
  MapList[0] = Header->Int4Map->PutTableSize();
  MapList[1] = Header->DoubleMap->PutTableSize();
  MapList[2] = Header->StringMap->PutTableSize();
  MapList[3] = Header->Int4VectorMap->PutTableSize();
  MapList[4] = Header->DoubleVectorMap->PutTableSize();
  MapList[5] = Header->StringVectorMap->PutTableSize();

  std::vector< std::string > KeyList;
  for (UInt4 i=0;i<MapList[0];i++) KeyList.push_back(Header->Int4Map->PutKey(i));
  for (UInt4 i=0;i<MapList[1];i++) KeyList.push_back(Header->DoubleMap->PutKey(i));
  for (UInt4 i=0;i<MapList[2];i++) KeyList.push_back(Header->StringMap->PutKey(i));
  for (UInt4 i=0;i<MapList[3];i++) KeyList.push_back(Header->Int4VectorMap->PutKey(i));
  for (UInt4 i=0;i<MapList[4];i++) KeyList.push_back(Header->DoubleVectorMap->PutKey(i));
  for (UInt4 i=0;i<MapList[5];i++) KeyList.push_back(Header->StringVectorMap->PutKey(i));


  Write( &MapList, gid, "MapList" );
  Write( &KeyList, gid, "KeyList" );

  for (UInt4 i=0;i<MapList[0];i++){
    Write( ( Header->Int4Map->Put(i) ), gid, Header->Int4Map->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[1];i++){
    Write( ( Header->DoubleMap->Put(i) ), gid, Header->DoubleMap->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[2];i++){
    Write( ( Header->StringMap->Put(i) ), gid, Header->StringMap->PutKey(i) );
  }

  for (UInt4 i=0;i<MapList[3];i++){
    std::vector<Int4> d = Header->Int4VectorMap->Put(i);
    Write( &d, gid, Header->Int4VectorMap->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[4];i++){
    std::vector<Double> d = Header->DoubleVectorMap->Put(i);
    Write( &d, gid, Header->DoubleVectorMap->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[5];i++){
    std::vector<std::string> d = Header->StringVectorMap->Put(i);
    Write( &d, gid, Header->StringVectorMap->PutKey(i) );
  }

  H5Gclose( gid );

}

///////////////////////////////////////////////////////
void ManyoDataIO::Write( std::vector<Double> *vec,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &( vec->front() ), (UInt4)(vec->size()), CurrentGID, DataName );
}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( std::vector<std::string> *vec,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &( vec->front() ), (UInt4)(vec->size()), CurrentGID, DataName );
}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( std::vector<Int4> *vec,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &( vec->front() ), (UInt4)(vec->size()), CurrentGID, DataName );
}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( std::vector<UInt4>  *vec,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &( vec->front() ), (UInt4)(vec->size()), CurrentGID, DataName );
}
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/*
void ManyoDataIO::WriteTest( std::vector<std::string> *dat,
                             const std::string &FileName,
                             const std::string &Username,
                             const UInt4 &MaxLength ){

  hid_t fileID =  CreateNewFile( FileName, Username );
  hid_t nexusID = PrepareNeXus( fileID );
  hid_t groupID = MakeNewDataGroup( nexusID, "Data1" );

  hid_t gid = MakeNewDataGroup( groupID, "TestData" );

  Write2( dat, gid, "TestString" );

  H5Gclose( gid );
  H5Gclose( groupID );
  H5Gclose( nexusID );
  H5Fclose( fileID );
}
////////////////////////////////////////////////////
void ManyoDataIO::Write2( std::vector<std::string> *vec,
                          hid_t CurrentGID,
                          const std::string &DataName,
                          const UInt4 &MaxLength ){
  Write2( &( vec->front() ), vec->size(), CurrentGID, DataName );
}
////////////////////////////////////////////////////
void ManyoDataIO::Write2( std::string *val, const UInt4 &size,
                          hid_t CurrentGID, const std::string &DataName,
                          const UInt4 &MaxLength ){

  // プロトタイピング中
  hsize_t dims[1];
  dims[0] = (hsize_t)size;

  Char wdata [ size ][ MaxLength ];

  // コピーが発生するので遅いかも
  // 直す余地あり
  for( UInt4 i=0; i<size; i++ ){ strcpy( wdata[i], val[i].c_str() ); }

  hid_t filetype = H5Tcopy( H5T_C_S1 );
  hid_t status = H5Tset_size( filetype, MaxLength );
  hid_t memtype = H5Tcopy( H5T_C_S1 );
  status = H5Tset_size( memtype, MaxLength );

  hid_t space = H5Screate_simple( 1, dims, NULL );
  hid_t dset = H5Dcreate( CurrentGID, DataName.c_str(),
                          filetype, space,
                          H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT );
  status = H5Dwrite( dset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata[0] );

  status = H5Dclose( dset );
  status = H5Sclose( space );
  status = H5Tclose( filetype );
  status = H5Tclose( memtype );

}
///////////////////////////////////////////////////////
void ManyoDataIO::
Write2( HeaderBase *Header,
        hid_t CurrentGID, const std::string &DataName ){

  hid_t gid;

  if( DataName == "" ){
    gid = MakeNewDataGroup( CurrentGID, "HeaderBase" );
  }
  else{
    gid = MakeNewDataGroup( CurrentGID, DataName );
  }


  std::vector<UInt4> MapList(6);
  MapList[0] = Header->Int4Map->PutTableSize();
  MapList[1] = Header->DoubleMap->PutTableSize();
  MapList[2] = Header->StringMap->PutTableSize();
  MapList[3] = Header->Int4VectorMap->PutTableSize();
  MapList[4] = Header->DoubleVectorMap->PutTableSize();
  MapList[5] = Header->StringVectorMap->PutTableSize();

  std::vector< std::string > KeyList;
  for (UInt4 i=0;i<MapList[0];i++) KeyList.push_back(Header->Int4Map->PutKey(i));
  for (UInt4 i=0;i<MapList[1];i++) KeyList.push_back(Header->DoubleMap->PutKey(i));
  for (UInt4 i=0;i<MapList[2];i++) KeyList.push_back(Header->StringMap->PutKey(i));
  for (UInt4 i=0;i<MapList[3];i++) KeyList.push_back(Header->Int4VectorMap->PutKey(i));
  for (UInt4 i=0;i<MapList[4];i++) KeyList.push_back(Header->DoubleVectorMap->PutKey(i));
  for (UInt4 i=0;i<MapList[5];i++) KeyList.push_back(Header->StringVectorMap->PutKey(i));


  Write( &MapList, gid, "MapList" );
  Write2( &KeyList, gid, "KeyList" );

  for (UInt4 i=0;i<MapList[0];i++){
    Write( ( Header->Int4Map->Put(i) ), gid, Header->Int4Map->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[1];i++){
    Write( ( Header->DoubleMap->Put(i) ), gid, Header->DoubleMap->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[2];i++){
    Write( ( Header->StringMap->Put(i) ), gid, Header->StringMap->PutKey(i) );
  }

  for (UInt4 i=0;i<MapList[3];i++){
    std::vector<Int4> d = Header->Int4VectorMap->Put(i);
    Write( &d, gid, Header->Int4VectorMap->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[4];i++){
    std::vector<Double> d = Header->DoubleVectorMap->Put(i);
    Write( &d, gid, Header->DoubleVectorMap->PutKey(i) );
  }
  for (UInt4 i=0;i<MapList[5];i++){
    std::vector<std::string> d = Header->StringVectorMap->Put(i);
    Write2( &d, gid, Header->StringVectorMap->PutKey(i) );
  }

  H5Gclose( gid );

}
*/

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
void ManyoDataIO::Write( std::string *val, const UInt4 &size,
                         hid_t CurrentGID, const std::string &DataName ){


  hid_t gid = MakeNewDataGroup( CurrentGID, DataName );

  hsize_t dims[ 1 ];
  dims[ 0 ] = (hsize_t)1;

  for( UInt4 i=0; i<size; i++ ){
    hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );
    hid_t atype = H5Tcopy( H5T_C_S1 );
    H5Tset_size( atype, val[i].size() );
    hid_t dat = H5Dcreate( gid, val[i].c_str(), atype, dataspace_id,
                           H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
    herr_t status = H5Dwrite( dat,
                              atype, // Char
                              H5S_ALL, H5S_ALL, H5P_DEFAULT,
                              val[i].c_str() );
    status = H5Dclose( dat );
    H5Tclose( atype );
    H5Sclose( dataspace_id );
  }
  H5Gclose( gid );

}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( UInt4  *val, const UInt4 &size,
                         hid_t CurrentGID, const std::string &DataName ){
  hsize_t dims[ 1 ];
  dims[ 0 ] = (hsize_t)size;
  hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );
  hid_t dataset_id = H5Dcreate2( CurrentGID, DataName.c_str(),
                                 H5T_STD_U32LE, // UInt4
                                 dataspace_id,
                                 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
  herr_t status = H5Dwrite( dataset_id,
                            H5T_NATIVE_UINT, // UInt4
                            H5S_ALL, H5S_ALL, H5P_DEFAULT,
                            val );
  status = H5Dclose( dataset_id );
  H5Sclose( dataspace_id );
}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( Int4   *val, const UInt4 &size,
                         hid_t CurrentGID, const std::string &DataName ){
  hsize_t dims[ 1 ];
  dims[ 0 ] = (hsize_t)size;
  hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );
  hid_t dataset_id = H5Dcreate2( CurrentGID, DataName.c_str(),
                                 H5T_STD_I32LE, // Int4
                                 dataspace_id,
                                 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
  herr_t status = H5Dwrite( dataset_id,
                            H5T_NATIVE_INT, // Int4
                            H5S_ALL, H5S_ALL, H5P_DEFAULT,
                            val );
  status = H5Dclose( dataset_id );
  H5Sclose( dataspace_id );
}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( Double *val, const UInt4 &size,
                         hid_t CurrentGID, const std::string &DataName ){
  hsize_t dims[ 1 ];
  dims[ 0 ] = (hsize_t)size;
  hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );
  hid_t dataset_id = H5Dcreate2( CurrentGID, DataName.c_str(),
                                 H5T_IEEE_F64LE, // Double
                                 dataspace_id,
                                 H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
  herr_t status = H5Dwrite( dataset_id,
                            H5T_NATIVE_DOUBLE, // Double
                            H5S_ALL, H5S_ALL, H5P_DEFAULT,
                            val );
  status = H5Dclose( dataset_id );
  H5Sclose( dataspace_id );
}
///////////////////////////////////////////////////////



///////////////////////////////////////////////////////
void ManyoDataIO::Write( const std::string &val,
                         hid_t CurrentGID,
                         const std::string &DataName ){

  hsize_t dims[ 1 ];
  dims[ 0 ] = (hsize_t)1;
  hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );
  hid_t atype = H5Tcopy( H5T_C_S1 );
  H5Tset_size( atype, val.size() );

  hid_t dat = H5Dcreate( CurrentGID, DataName.c_str(), atype, dataspace_id,
                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
  herr_t status = H5Dwrite( dat,
                            atype, // Char
                            H5S_ALL, H5S_ALL, H5P_DEFAULT,
                            val.c_str() );
  status = H5Dclose( dat );
  H5Tclose( atype );
  H5Sclose( dataspace_id );

}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( UInt4  val,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &val, 1, CurrentGID, DataName );
}
///////////////////////////////////////////////////////
void ManyoDataIO::Write( Int4   val,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &val, 1, CurrentGID, DataName );
}
//////////////////////////////////////////////////////
void ManyoDataIO::Write( Double val,
                         hid_t CurrentGID,
                         const std::string &DataName ){
  Write( &val, 1, CurrentGID, DataName );
}

//////////////////////////////////////////////////////////




///////////////
std::string ManyoDataIO::PutDataType( const std::string &FileName )
{
  std::string data_type("Unknown");
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    return data_type;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata;
  ecdata = H5Gopen2( data1, "ElementContainerMatrixData", H5P_DEFAULT );
  if (ecdata >= 0){
    data_type = "ElementContainerMatrix";
    H5Gclose( ecdata );
  }else{
    ecdata = H5Gopen2( data1, "ElementContainerArrayData", H5P_DEFAULT );
    if (ecdata >= 0){
      data_type = "ElementContainerArray";
      H5Gclose( ecdata );
    }else{
      ecdata = H5Gopen2( data1, "ElementContainerData", H5P_DEFAULT );
      if (ecdata >= 0){
        data_type = "ElementContainer";
        H5Gclose( ecdata );
      }
    }
  }
  H5Gclose( data1 );
  H5Gclose( gid );
  H5Fclose( fid );
  return data_type;
}
///////////////
ElementContainerMatrix * ManyoDataIO::ReadElementContainerMatrix( const std::string &FileName )
{
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );
  if (fid<0){ // Failed to open file.
      std::cout << "Failed to open file ( "+FileName+" )" << std::endl;
      ElementContainerMatrix *M = NULL;
      return M;
  }

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    std::cout << "null pointer returns.";
    ElementContainerMatrix *M = NULL;
    return M;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata = H5Gopen2( data1, "ElementContainerMatrixData", H5P_DEFAULT );
  if (ecdata < 0){ // Failed to open the group.
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    std::cout << FileName << " is wrong, please check." << std::endl;
    return NULL;
  }else{
    ElementContainerMatrix *M = new ElementContainerMatrix();
    Read( ecdata, M );

    H5Gclose( ecdata );
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    return M;
  }
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, ElementContainerMatrix *M ){
  hid_t ecdata = H5Gopen2( CurrentGID, DataName.c_str(), H5P_DEFAULT );
  Read( ecdata, M);
  H5Gclose( ecdata );
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, ElementContainerMatrix *M ){

  HeaderBase H;
  Read( CurrentGID, "HeaderBase_in_ElementContainerMatrix", H );
  M -> InputHeader( H );

  UInt4 size;
  Read( CurrentGID, "size", size );

  for( UInt4 i=0; i<size; i++ ){
    ElementContainerArray *A = new ElementContainerArray();
    Read( CurrentGID, "ElementContainerArray"+tostr( i ), A );
    M -> AddPointer( A );
  }
}
///////////////
ElementContainerArray * ManyoDataIO::ReadElementContainerArray( const std::string &FileName )
{
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );
  if (fid<0){ // Failed to open file.
      std::cout << "Failed to open file ( "+FileName+" )" << std::endl;
      ElementContainerArray *M = NULL;
      return M;
  }

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    std::cout << "null pointer returns.";
    ElementContainerArray *M = NULL;
    return M;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata = H5Gopen2( data1, "ElementContainerArrayData", H5P_DEFAULT );
  if (ecdata < 0){ // Failed to open the group.
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    std::cout << FileName << " is wrong, please check." << std::endl;
    return NULL;
  }else{
    ElementContainerArray *A = new ElementContainerArray();
    Read( ecdata, A );

    H5Gclose( ecdata );
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    return A;
  }
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, ElementContainerArray *A ){
  hid_t ecdata = H5Gopen2( CurrentGID, DataName.c_str(), H5P_DEFAULT );
  Read( ecdata, A);
  H5Gclose( ecdata );
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, ElementContainerArray *A ){

  HeaderBase H;
  Read( CurrentGID, "HeaderBase_in_ElementContainerArray", H );
  A -> InputHeader( H );

  UInt4 size;
  Read( CurrentGID, "size", size );

  for( UInt4 i=0; i<size; i++ ){
    ElementContainer *E = new ElementContainer();
    Read( CurrentGID, "ElementContainer"+tostr( i ), E );
    A -> AddPointer( E );
  }
}
///////////////
ElementContainer * ManyoDataIO::ReadElementContainer( const std::string &FileName )
{
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );
  if (fid<0){ // Failed to open file.
      std::cout << "Failed to open file ( "+FileName+" )" << std::endl;
      ElementContainer *M = NULL;
      return M;
  }

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    std::cout << "null pointer returns.";
    ElementContainer *M = NULL;
    return M;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata = H5Gopen2( data1, "ElementContainerData", H5P_DEFAULT );
  if (ecdata < 0){ // Failed to open the group.
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    std::cout << FileName << " is wrong, please check." << std::endl;
    return NULL;
  }else{
    ElementContainer *EC = new ElementContainer();
    Read( ecdata, EC );

    H5Gclose( ecdata );
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    return EC;
  }
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, ElementContainer *EC ){
  hid_t ecdata = H5Gopen2( CurrentGID, DataName.c_str(), H5P_DEFAULT );
  Read( ecdata, EC);
  H5Gclose( ecdata );
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, ElementContainer *EC ){

  HeaderBase H;
  Read( CurrentGID, "HeaderBase_in_ElementContainer", H );
  EC -> InputHeader( H );

  HeaderBase HU;
  Read( CurrentGID, "UnitHeader_in_ElementContainer", HU );
  //EC -> InputUnitHeader( HU );

  std::vector<std::string> KeyList;
  Read( CurrentGID, "KeyList", KeyList );

  for( UInt4 i=0; i<KeyList.size(); i++ ){
    std::vector<Double> v;
    Read( CurrentGID, KeyList[i], v );
    EC -> Add( KeyList[i], v, HU.PutString(KeyList[i]) );
  }

  std::string xkey, ykey, ekey;
  Read( CurrentGID, "Xkey", xkey );
  Read( CurrentGID, "Ykey", ykey );
  Read( CurrentGID, "Ekey", ekey );

  if( !( xkey=="None" || ykey=="None" || ekey=="None" ) ){
    bool ret = EC -> SetKeys( xkey, ykey, ekey );
    if (_status) _status= ret;
  }
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, std::vector<Double> &vd ){

  hid_t dataset = H5Dopen( CurrentGID, DataName.c_str(), H5S_ALL );
  //hid_t dataset_space = H5Dget_space( dataset );
  UInt4 VecSize = (UInt4)(H5Dget_storage_size( dataset )) / 8;
  vd.resize( VecSize );
  H5Dread( dataset, H5T_IEEE_F64LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &(vd[0]) );
  H5Dclose( dataset );
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, std::string &s ){

  hid_t dataset = H5Dopen2( CurrentGID, DataName.c_str(), H5S_ALL );
  //hid_t dataset_space = H5Dget_space( dataset );
  UInt4 csize = (UInt4)(H5Dget_storage_size( dataset ));
  Char *c = new Char [csize];

  //hsize_t *dims = new hsize_t [1];
  //dims[ 0 ] = (hsize_t)1;
  //hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );

  hid_t atype = H5Tcopy( H5T_C_S1 );
  H5Tset_size( atype, csize );

  H5Dread( dataset, atype, H5S_ALL, H5S_ALL, H5P_DEFAULT, c );

  //s.resize( 0 );
  //s.append( c );
  //s.resize( csize );
  s.clear();
  s.append( c, csize );

  H5Dclose( dataset );
  H5Tclose( atype );
  //delete [] dims;
  delete [] c;
}
//////////////

void ManyoDataIO::ReadVersion( hid_t CurrentGID, const std::string &DataName, std::string &s ){

  hid_t dataset = H5Dopen2( CurrentGID, DataName.c_str(), H5S_ALL );
  if( dataset < 0 ){
    s.resize( 0 );
    s = "null";
    return;
  }


  //hid_t dataset_space = H5Dget_space( dataset );
  UInt4 csize = (UInt4)(H5Dget_storage_size( dataset ));
  Char *c = new Char [csize];

  //hsize_t *dims = new hsize_t [1];
  //dims[ 0 ] = (hsize_t)1;
  //hid_t dataspace_id = H5Screate_simple( (hsize_t)1, dims, NULL );

  hid_t atype = H5Tcopy( H5T_C_S1 );
  H5Tset_size( atype, csize );

  H5Dread( dataset, atype, H5S_ALL, H5S_ALL, H5P_DEFAULT, c );

  //s.resize( 0 );
  //s.append( c );
  //s.resize( csize );
  s.clear();
  s.append( c, csize );

  H5Dclose( dataset );
  H5Tclose( atype );
  //delete [] dims;
  delete [] c;
}
//////////////

void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, HeaderBase &h ){

  std::string st;
  Read( CurrentGID, DataName, st );
  if (st!="")
      h.InputString( st );
  else
      _status = false;
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, std::vector<std::string> &vs ){

  std::string s0;
  Read( CurrentGID, DataName, s0 );

  std::vector<std::string> tmp = st -> SplitString( s0, "," );

  vs.clear();
  for( UInt4 i=0; i<tmp.size(); i++ ){
    vs.push_back( tmp[i] );
  }
}
//////////////
void ManyoDataIO::Read( hid_t CurrentGID, const std::string &DataName, UInt4 &i ){

  hid_t dataset = H5Dopen2( CurrentGID, DataName.c_str(), H5S_ALL );
  hid_t size_id = H5Dread( dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i );
  H5Dclose( dataset );
}

//////////////
bool ManyoDataIO::Read( ElementContainerMatrix* M, const std::string &FileName )
{
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );
  if (fid<0){ // Failed to open file.
      std::cout << "Failed to open file ( "+FileName+" )" << std::endl;
      return false;
  }

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    std::cout << "null pointer returns.";
    return false;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata = H5Gopen2( data1, "ElementContainerMatrixData", H5P_DEFAULT );
  if (ecdata < 0){ // Failed to open the group.
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    std::cout << FileName << " is wrong, please check." << std::endl;
    return false;
  }else{
    _status = true;
    Read( ecdata, M );

    H5Gclose( ecdata );
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    return _status;
  }
}
///////////////
bool ManyoDataIO::Read( ElementContainerArray* A, const std::string &FileName )
{
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );
  if (fid<0){ // Failed to open file.
      std::cout << "Failed to open file ( "+FileName+" )" << std::endl;
      return false;
  }

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    std::cout << "null pointer returns.";
    return false;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata = H5Gopen2( data1, "ElementContainerArrayData", H5P_DEFAULT );
  if (ecdata < 0){ // Failed to open the group.
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    std::cout << FileName << " is wrong, please check." << std::endl;
    return false;
  }else{
    _status = true;
    Read( ecdata, A );

    H5Gclose( ecdata );
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    return _status;
  }
}
///////////////
bool ManyoDataIO::Read( ElementContainer* E, const std::string &FileName )
{
  hid_t fid = H5Fopen( FileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT );
  if (fid<0){ // Failed to open file.
      std::cout << "Failed to open file ( "+FileName+" )" << std::endl;
      return false;
  }

  std::string version;
  ReadVersion( fid, "version", version );

  if( version != "2016" ){
    H5Fclose( fid );
    std::cout << "The version of this NeXus file is not 2016." << std::endl;
    std::cout << "null pointer returns.";
    return false;
  }

  hid_t gid = H5Gopen2( fid, "Entry1", H5P_DEFAULT );
  hid_t data1 = H5Gopen2( gid, "Data1", H5P_DEFAULT );

  hid_t ecdata = H5Gopen2( data1, "ElementContainerData", H5P_DEFAULT );
  if (ecdata < 0){ // Failed to open the group.
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    std::cout << FileName << " is wrong, please check." << std::endl;
    return false;
  }else{
    _status = true;
    Read( ecdata, E );

    H5Gclose( ecdata );
    H5Gclose( data1 );
    H5Gclose( gid );
    H5Fclose( fid );
    return _status;
  }
}
