/*
$Id: ReadNeXusFile.cc 2247 2011-04-27 05:20:41Z jisuzuki $
 */

#include "ReadNeXusFile.hh"
////////////////////////////////////////
ReadNeXusFile::
ReadNeXusFile( const std::string &FileName )
{
  OpenNeXusFile( FileName );
  CurrentNumber = 0;
  ss = new SplitString();
  w_handleFlag = 0;
}
////////////////////////////////////////
ReadNeXusFile::
ReadNeXusFile( NXhandle w_handle )
{
  handle = w_handle;
  CurrentNumber = 0;
  ss = new SplitString();
  w_handleFlag = 1;
}
////////////////////////////////////////
ReadNeXusFile::
~ReadNeXusFile()
{
  if( w_handleFlag == 0 ){
    CloseNeXusFile();
  }
  delete ss;
}
////////////////////////////////////////
void ReadNeXusFile::
ReadData1( UInt4ContainerMatrix &m )
{
  UInt4 size = ReadDataUInt4( "size" );
  HeaderBase header = ReadHeaderBase1( "HeaderBase_in_UInt4ContainerMatrix" );
  m.InputHeader( header );

  for( UInt4 i=0; i<size; i++ ){
    std::string name = "UInt4ContainerArray";
    Char *index = new Char[ 128 ];
    std::snprintf( index, sizeof(index), "%d", i );
    name = name + std::string( index );
    delete [] index;
    UInt4ContainerArray a = ReadUInt4ContainerArray1( name.c_str() );
    m.Add( a );
  }
}
////////////////////////////////////////
void ReadNeXusFile::
ReadData1( ElementContainerMatrix &m)
{
  UInt4 size = ReadDataUInt4( "size" );
  HeaderBase header = ReadHeaderBase1( "HeaderBase_in_ElementContainerMatrix" );
  m.InputHeader( header );

  for( UInt4 i=0; i<size; i++ ){
    std::string name = "ElementContainerArray";
    Char *index = new Char[ 128 ];
    std::snprintf( index, sizeof(index), "%d", i );
    name = name + std::string( index );
    delete [] index;
    ElementContainerArray a = ReadElementContainerArray1( name.c_str() );
    m.Add( a );
  }
}
////////////////////////////////////////
void ReadNeXusFile::
OpenNeXusFile( const std::string &FileName )
{
  NXopen( FileName.c_str(), NXACC_RDWR, &handle );
}
///////////////////////////////////////
void ReadNeXusFile::
CloseNeXusFile()
{
  NXclose( &handle );
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, std::string &s )
{
  OpenData( Name );
  std::vector<Int4> vi = GetInfo();
  Int4 size = vi[ 0 ];
  Char *c = new Char [ size+1 ];

  NXgetdata( handle, c );
  CloseData();

  c[size] = '\0';

  s = std::string( c );

  delete [] c;

}
//////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, UInt4 &i )
{
  OpenData( Name );

  NXgetdata( handle, &i );
  CloseData();
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, Int4 &i )
{
  OpenData( Name );

  NXgetdata( handle, &i );
  CloseData();
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, Double &d )
{
  OpenData( Name );

  NXgetdata( handle, &d );
  CloseData();
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData1( HeaderBase &H )
{
  HeaderBase header;

  std::vector<UInt4> MapList = ReadUInt4Vector("MapList");
  std::vector< std::string > KeyList = ReadStringVector("KeyList");

  UInt4 KeyIndex=0;

  if (MapList[0]>0)
    for (UInt4 i=0;i<MapList[0];++i) {
      header.Add(KeyList[KeyIndex], ReadDataInt4(KeyList[KeyIndex]));
      ++KeyIndex;
    }
  if (MapList[1]>0)
    for (UInt4 i=0;i<MapList[1];++i) {
      header.Add(KeyList[KeyIndex], ReadDataDouble(KeyList[KeyIndex]));
      ++KeyIndex;
    }
  if (MapList[2]>0)
    for (UInt4 i=0;i<MapList[2];++i) {
      header.Add(KeyList[KeyIndex], ReadDataString(KeyList[KeyIndex]));
      ++KeyIndex;
    }
  if (MapList[3]>0)
    for (UInt4 i=0;i<MapList[3];++i) {
      header.Add(KeyList[KeyIndex], ReadInt4Vector(KeyList[KeyIndex]));
      ++KeyIndex;
    }
  if (MapList[4]>0)
    for (UInt4 i=0;i<MapList[4];++i) {
      header.Add(KeyList[KeyIndex], ReadDoubleVector(KeyList[KeyIndex]));
      ++KeyIndex;
    }
  if (MapList[5]>0)
    for (UInt4 i=0;i<MapList[5];++i) {
      header.Add(KeyList[KeyIndex], ReadStringVector(KeyList[KeyIndex]));
      ++KeyIndex;
    }

  H = header;
}
///////////////////////////////////////
void  ReadNeXusFile::
ReadData1( UInt4ContainerArray &a )
{
  UInt4 size = ReadDataUInt4( "size" );
  HeaderBase header = ReadHeaderBase1( "HeaderBase_in_UInt4ContainerArray" );
  a.InputHeader( header );

  for( UInt4 i=0; i<size; i++ ){
    std::string name = "UInt4Container";
    Char *index = new Char[ 128 ];
    std::snprintf( index, sizeof(index), "%d", i );
    name = name + std::string( index );
    delete [] index;
    UInt4Container e = ReadUInt4Container1( name.c_str() );
    a.Add( e );
  }
}
/////////////////////////////////////////
void  ReadNeXusFile::
ReadData1( ElementContainerArray &a )
{
  UInt4 size = ReadDataUInt4( "size" );
  HeaderBase header = ReadHeaderBase1( "HeaderBase_in_ElementContainerArray" );
  a.InputHeader( header );

  for( UInt4 i=0; i<size; i++ ){
    std::string name = "ElementContainer";
    Char *index = new Char[ 128 ];
    std::snprintf( index, sizeof(index), "%d", i );
    name = name + std::string( index );
    delete [] index;
    ElementContainer e = ReadElementContainer1( name.c_str() );
    a.Add( e );
  }
}
///////////////////////////////////////
void  ReadNeXusFile::
ReadData1( UInt4Container &U )
{
  HeaderBase h = ReadHeaderBase1( "HeaderBase_in_UInt4Container" );
  U.InputHeader( h );

  std::string KeyList = ReadDataString( "KeyList" );
  UInt4  size    = ReadDataUInt4(  "size" );

  if( KeyList != "NULL" ){
    std::vector<std::string> Key = ss->Split( KeyList, "," );

    if( size != Key.size() ){
      std::cerr << "ReadNeXusFile::ReadUInt4Container(std::string)" << std::endl;
      std::cerr << "The number of vectors are mismatched." << std::endl;
    }

    for( UInt4 i=0; i<Key.size(); i++ ){
      std::string TargetName = Key[ i ];
      U.Add( TargetName, ReadUInt4Vector( TargetName ) );
    }
  }
}
///////////////////////////////////////
TwoDimElementContainer ReadNeXusFile::
ReadTwoDimElementContainer( const std::string &Name ){
  OpenGroup( Name, "NXdata" ); // Open the target directory


  HeaderBase header = ReadHeaderBase1( "HeaderBase_in_TwoDimElementContainer" );
  std::vector<UInt4> DimVec = ReadUInt4Vector( "DimensionVector" );
  TwoDimElementContainer TDE( DimVec );
  TDE.InputHeader( header );
  std::vector<ElementContainer> ve;
  ve.clear();

  UInt4 Total = 0;
  for( UInt4 i=0; i<DimVec.size(); i++ ){
    Total = Total + DimVec[ i ];
  }

  Char *buf = new Char[10];
  for( UInt4 i=0; i<Total; i++ ){
    std::string name = "ElementContainer_";
    std::snprintf( buf, sizeof(buf), "%d", i );
    name = name + std::string( buf );
    ve.push_back( ReadElementContainer1( name ) );
  }
  delete [] buf;
  TDE.InputPackedContainer( ve );
  return TDE;
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData1( ElementContainer &E )
{
  HeaderBase h = ReadHeaderBase1( "HeaderBase_in_ElementContainer" );
  E.InputHeader( h );

  HeaderBase uh = ReadHeaderBase1( "UnitHeader_in_ElementContainer" );
  //E.InputUnitHeader( uh );

  std::string KeyList = ReadDataString( "KeyList" );
  std::string Xkey    = ReadDataString( "Xkey" );
  std::string Ykey    = ReadDataString( "Ykey" );
  std::string Ekey    = ReadDataString( "Ekey" );
  UInt4  size    = ReadDataUInt4(  "size" );

  if( KeyList != "NULL" ){
    std::vector<std::string> Key = ss->Split( KeyList, "," );

    if( size != Key.size() ){
      std::cerr << "ReadNeXusFile::ReadElementContainer(std::string)" << std::endl;
      std::cerr << "The number of vectors are mismatched." << std::endl;
    }

    for( UInt4 i=0; i<Key.size(); i++ ){
      std::string TargetName = Key[ i ];
      E.Add( TargetName, ReadDoubleVector( TargetName ),
        uh.PutString( TargetName ) );
    }

    if( !( Xkey=="None" || Ykey=="None" || Ekey=="None" ) ){
      E.SetKeys( Xkey, Ykey, Ekey );
    }
  }
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, std::vector<std::string> &vs )
{

  OpenGroup( Name, "NXdata" );
  std::vector<std::string> getgroupinfo = GetGroupInfo();
  Int4 size = PutCurrentNumber();

  vs.resize(size);

  for( Int4 i=0; i<size; i++ ){
    std::vector<std::string> getnextentry2 = GetNextEntry();
    ReadData(getnextentry2[0], vs[i]);
  }

  CloseGroup();
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, std::vector<Double> &vd )
{
  OpenData( Name );
  std::vector<Int4> v = GetInfo();
  UInt4 size = (UInt4) v[ 0 ];

  vd.resize(size);
  NXgetdata( handle, &(vd[0]) );
  CloseData();    // [Inamura 140403]
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, std::vector<Int4> &vi )
{
  OpenData( Name );
  std::vector<Int4> v = GetInfo();
  UInt4 size = (UInt4) v[ 0 ];

  vi.resize(size);
  NXgetdata( handle, &(vi[0]) );
  CloseData();    // [Inamura 140403]
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, std::vector<UInt4> &vi )
{
  OpenData( Name );
  std::vector<Int4> v = GetInfo();
  UInt4 size = (UInt4) v[ 0 ];

  vi.resize(size);
  NXgetdata( handle, &(vi[0]) );
  CloseData();    // [Inamura 140403]
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, std::vector< std::vector<Double> > &vvd )
{
  OpenData( Name );
  std::vector<Int4> rv = GetInfo2d();
  UInt4 size = (UInt4)( rv[0]*rv[1] );

  std::vector<Double> v;
  v.resize(size);
  NXgetdata( handle, &(v[0]) );
  CloseData();

  for (Int4 i=0; i<rv[0]; i++){
      std::vector<Double> tmp;
      tmp.clear();
      for (Int4 j=0; j<rv[1]; j++){
          tmp.push_back( v[ i*rv[1] + j ] );
      }
      vvd.push_back(tmp);
  }
}
///////////////////////////////////////
void ReadNeXusFile::
ReadData( const std::string &Name, bool &f)
{
    Int4 r;
    ReadData( Name, r );
    if (r==1) f = true;
    else f = false;
}
///////////////////////////////////////
std::vector<Int4> ReadNeXusFile::
GetInfo2d()
{
  Int4 Rank;
  Int4 *Dimension = new Int4 [ 256 ];
  Int4 DataType;

  NXgetinfo( handle, &Rank, Dimension, &DataType );
  std::vector<Int4> v;
  v.clear();
  for (Int4 i=0; i<Rank; i++)
      v.push_back( Dimension[i] );

  v.push_back( DataType );
  CurrentNumber = Rank;

  delete [] Dimension;
  return v;
}
///////////////////////////////////////
std::vector<Int4> ReadNeXusFile::
GetInfo()
{
  Int4 Rank;
  Int4 *Dimension = new Int4 [ 256 ];
  Int4 DataType;

  NXgetinfo( handle, &Rank, Dimension, &DataType );
  std::vector<Int4> v;
  v.clear();
  v.push_back( Dimension[0] );
  v.push_back( DataType );
  CurrentNumber = Rank;

  delete [] Dimension;
  return v;
}
///////////////////////////////////////
void ReadNeXusFile::
OpenData( const std::string &DataSetName )
{
  NXstatus r=NXopendata( handle, DataSetName.c_str() );
  if (r!=NX_OK)
    std::cout << "OpenData fails. name="<<DataSetName<<" NXstatus = "<<r<<std::endl;
}
///////////////////////////////////////
void ReadNeXusFile::
OpenGroup( const std::string &GroupName, const std::string &GroupClass )
{
  NXstatus r=NXopengroup( handle, GroupName.c_str(), GroupClass.c_str() );
  if (r!=NX_OK)
    std::cout << "OpenGroup fails. name="<<GroupName<<" NXstatus = "<<r<<std::endl;
}
///////////////////////////////////////
std::vector<std::string> ReadNeXusFile::
GetNextEntry()
{
  std::vector<std::string> vs;
  vs.clear();

  Int4 Number;
  Char GroupName[256];
  Char GroupClass[256];
  NXgetnextentry( handle, GroupName, GroupClass, &Number );

  CurrentNumber = Number;
  vs.push_back( std::string( GroupName  ) );
  vs.push_back( std::string( GroupClass ) );

  return vs;
}
///////////////////////////////////////
std::vector<std::string> ReadNeXusFile::
GetGroupInfo()
{
  std::vector<std::string> vs;
  vs.clear();

  Int4 Number;
  Char GroupName[256];
  Char GroupClass[256];
  NXgetgroupinfo( handle, &Number, GroupName, GroupClass );

  CurrentNumber = Number;
  vs.push_back( std::string( GroupName  ) );
  vs.push_back( std::string( GroupClass ) );

  return vs;
}
