// =====================================================================
//  $Id: TInputObjectFile.cc,v 1.1.1.1 2003/06/27 02:56:41 goiwai Exp $
//  $Name: CLDAQ-1-06-02 $
// =====================================================================
#include "TInputObjectFile.hh"
#include "TStreamableObject.hh"
#include "TDataRecord.hh"
#include "TDataSection.hh"
#include "TDataSegment.hh"
#include "TDataElement.hh"
#include "TObjectFilter.hh"

TInputObjectFile::TInputObjectFile( const Tstring& filename, const Tstring& mode )
  : TObjectFile( filename, mode ), TInputObjectStream( tFileStream )
{;}

TInputObjectFile::TInputObjectFile( TObjectFilter* filter, const Tstring& filename, const Tstring& mode )
  : TObjectFile( filename, mode ), TInputObjectStream( filter, tFileStream )
{;}

TInputObjectFile::~TInputObjectFile()
{;}

Tint TInputObjectFile::Read( TStreamableObject& object )
{
  theLastDataSize = theDataSize;
  theDataSize = 0;

  if ( HasFilter() ) {
    return( theObjectFilter -> Filtering( object, this ) );
  }  

  static Tobject_t objecttype = object.GetObjectType();

  switch ( objecttype ) {
    case tObjectDataRecord:
      *( (TDataRecord*)(&object) ) = getDataRecord();
      break;
    case tObjectDataSection:
      *( (TDataSection*)(&object) ) = getDataSection();
      break;
    case tObjectDataSegment:
      *( (TDataSegment*)(&object) ) = getDataSegment();
      break;
    case tObjectDataElement:
      *( (TDataElement*)(&object) ) = getDataElement();
      break;
    default:
      break;
  }

  theTotalDataSize += theDataSize;

  return( theDataSize );
}

TDataRecord TInputObjectFile::getDataRecord()
{
  Tint recsize;
  Tobject_t type;
  Tstring id;
  Tsize_t entries;

  readProperties( recsize, type, id, entries );

  TDataRecord record( id );
  record.SetObjectType( type );
  if ( theDataSize == 0 ) {
    return( record );
  }

  for ( Tsize_t i = 0; i < entries; i ++ ) {
    record.push_back( getDataSection() );
  }

  return( record );
}

TDataSection TInputObjectFile::getDataSection()
{
  Tint recsize;
  Tobject_t type;
  Tstring id;
  Tsize_t entries;
  readProperties( recsize, type, id, entries );

  TDataSection section( id );
  section.SetObjectType( type );
  if ( theDataSize == 0 ) {
    return( section );
  }

  for ( Tsize_t i = 0; i < entries; i ++ ) {
    section.push_back( getDataSegment() );
  }

  return( section );
}

TDataSegment TInputObjectFile::getDataSegment()
{
  Tint recsize;
  Tobject_t type;
  Tstring id;
  Tsize_t entries;
  readProperties( recsize, type, id, entries );


  TDataSegment segment( id );
  segment.SetObjectType( type );
  if ( theDataSize == 0 ) {
    return( segment );
  }

  for ( Tsize_t i = 0; i < entries; i ++ ) {
    segment.push_back( getDataElement() );
  }

  return( segment );
}

TDataElement TInputObjectFile::getDataElement()
{
  static const Tsize_t nmemb = 1;
  static const Tstring head = "TInputObjectFile::getDataElement";
  Tint recsize;
  Tobject_t otype;
  Tstring id;
  Telement_t etype;
  Tint nprvs;
  TDataElement element;


  // read record size
  if ( ( fread( &recsize, Tsizeof( Tint ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return( element );
  } else {
    theDataSize += Tsizeof( Tint );
  }


  // read object type
  if ( ( fread( &otype, Tsizeof( Tobject_t ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return( element );
  } else {
    theDataSize += Tsizeof( Tobject_t );
    element.SetObjectType( otype );
  }


  // read object id
  Tsize_t nchar;
  Tchar* charbuf = 0;
  if ( fread( &nchar, Tsizeof( Tsize_t ), nmemb, theFileStream ) != nmemb ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return( element );
  } else {
    theDataSize += Tsizeof( Tsize_t );
    charbuf = new Tchar[ nchar ];
  }
  if ( fread( charbuf, Tsizeof( Tchar ) * nchar, nmemb, theFileStream ) != nmemb ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    delete [] charbuf;
    return( element );
  } else {
    theDataSize += Tsizeof( Tchar ) * nchar;
    id = charbuf;
    delete [] charbuf;
    element.SetID( id );
  }



  // read element type
  if ( ( fread( &etype, Tsizeof( Telement_t ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return( element );
  } else {
    theDataSize += Tsizeof( Telement_t );
    element.SetElementType( etype );
  }


  // read number of primitives
  if ( ( fread( &nprvs, Tsizeof( Tint ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return( element );
  } else {
    theDataSize += Tsizeof( Tint );
    element.SetNumberOfPrimitives( nprvs );
  }


  Tstring* strbuf = 0;
  Tchar* cc = 0;
  Tint* ii = 0;
  TUint* ui = 0;
  Tdouble* dd = 0;
  TUshort* us = 0;
  Tshort* ss = 0;
  Tfloat* ff = 0;
  Tlong* ll = 0;
  TUlong* ul = 0;



  switch ( etype ) {

    case tTypeInt:
      ii = new Tint[ nprvs ];
      if ( fread( ii, Tsizeof( Tint ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] ii;
	return( element );
      } else {
	element.FillData( ii, nprvs );
	theDataSize += (Tint)( Tsizeof( Tint ) * nprvs );
	delete [] ii;
      }
      break;


    case tTypeUnsignedInt:
      ui = new TUint[ nprvs ];
      if ( fread( ui, Tsizeof( TUint ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] ui;
	return( element );
      } else {
	element.FillData( ui, nprvs );
	theDataSize += (Tint)( Tsizeof( TUint ) * nprvs );
	delete [] ui;
      }
      break;


    case tTypeWord:
    case tTypeUnsignedShort:
      us = new TUshort[ nprvs ];
      if ( fread( us, Tsizeof( TUshort ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] us;
	return( element );
      } else {
	element.FillData( us, nprvs );
	theDataSize += (Tint)( Tsizeof( TUshort ) * nprvs );
	delete [] us;
      }
      break;

    case tTypeDouble:
      dd = new Tdouble[ nprvs ];
      if ( fread( dd, Tsizeof( Tdouble ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] dd;
	return( element );
      } else {
	element.FillData( dd, nprvs );
	theDataSize += (Tint)( Tsizeof( Tdouble ) * nprvs );
	delete [] dd;
      }
      break;

    case tTypeFloat:
      ff = new Tfloat[ nprvs ];

      if ( fread( ff, Tsizeof( Tfloat ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] ff;
	return( element );
      } else {
	element.FillData( ff, nprvs );
	theDataSize += (Tint)( Tsizeof( Tfloat ) * nprvs );
	delete [] ff;
      }
      break;


    case tTypeShort:
      ss = new Tshort[ nprvs ];
      if ( fread( ss, Tsizeof( Tshort ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] ss;
	return( element );
      } else {
	element.FillData( ss, nprvs );
	theDataSize += (Tint)( Tsizeof( Tshort ) * nprvs );
	delete [] ss;
      }
      break;

    case tTypeLong:
      ll = new Tlong[ nprvs ];
      if ( fread( ll, Tsizeof( Tlong ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] ll;
	return( element );
      } else {
	element.FillData( ll, nprvs );
	theDataSize += (Tint)( Tsizeof( Tlong ) * nprvs );
	delete [] ll;
      }
      break;

    case tTypeUnsignedLong:
      ul = new TUlong[ nprvs ];
      if ( fread( ul, Tsizeof( TUlong ) * nprvs, nmemb, theFileStream ) != nmemb ) {
	//perror( head.c_str() );
	SetOffset( 0, SEEK_END );
	theDataSize = 0;
	delete [] ul;
	return( element );
      } else {
	element.FillData( ul, nprvs );
	theDataSize += (Tint)( Tsizeof( TUlong ) * nprvs );
	delete [] ul;
      }
      break;

    case tTypeString:
      strbuf = new Tstring[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	Tsize_t nchar;
	if ( fread( &nchar, Tsizeof( Tsize_t ), nmemb, theFileStream ) != nmemb ) {
	  //perror( head.c_str() );
	  SetOffset( 0, SEEK_END );
	  theDataSize = 0;
	  delete [] strbuf;
	  return( element );
	} else {
	  theDataSize += (Tint)( Tsizeof( Tsize_t ) * nmemb );
	  cc = new Tchar[ nchar ];
	}
	if ( fread( cc, Tsizeof( Tchar ) * nchar, nmemb, theFileStream ) != nmemb ) {
	  //perror( head.c_str() );
	  SetOffset( 0, SEEK_END );
	  theDataSize = 0;
	  delete [] cc;
	  delete [] strbuf;
	  return( element );
	} else {
	  theDataSize += (Tint)( Tsizeof( Tchar ) * nchar );
	}
	strbuf[ i ] = cc;
	delete [] cc;
      }
      element.FillData( strbuf, nprvs );
      delete [] strbuf;
      break;

    case tTypeUnknown:
    case tTypeObject:
    default:
      break;
  }

  return( element );
}

Tvoid TInputObjectFile::readProperties( Tint& recsize, Tobject_t& type, Tstring& id, Tsize_t& entries )
{
  static const Tsize_t nmemb = 1;
  static const Tstring head = "TInputObjectFile::readProperties";

  // read record size
  if ( ( fread( &recsize, Tsizeof( Tint ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return;
  } else {
    theDataSize += Tsizeof( Tint );
  }


  // read object type
  if ( ( fread( &type, Tsizeof( Tobject_t ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return;
  } else {
    theDataSize += Tsizeof( Tobject_t );
  }

  // read object id
  Tsize_t nchar;
  Tchar* charbuf = 0;
  if ( fread( &nchar, Tsizeof( Tsize_t ), nmemb, theFileStream ) != nmemb ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return;
  } else {
    theDataSize += Tsizeof( Tsize_t );
    charbuf = new Tchar[ nchar ];
  }
  if ( fread( charbuf, Tsizeof( Tchar ) * nchar, nmemb, theFileStream ) != nmemb ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    delete [] charbuf;
    return;
  } else {
    theDataSize += Tsizeof( Tchar ) * nchar;
  }
  id = charbuf;
  delete [] charbuf;

  // read entries
  if ( ( fread( &entries, Tsizeof( Tsize_t ), nmemb, theFileStream ) != nmemb ) ) {
    //perror( head.c_str() );
    SetOffset( 0, SEEK_END );
    theDataSize = 0;
    return;
  } else {
    theDataSize += Tsizeof( Tsize_t );
  }

  return;
}
