// =====================================================================
//  $Id: TInputObjectSharedMemory.cc,v 1.5 2004/03/07 10:30:32 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: TInputObjectSharedMemory.cc,v $
//  Revision 1.5  2004/03/07 10:30:32  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.4  2003/12/06 10:56:19  goiwai
//  フィルタ関連の修整と Read(),Write()の戻り値の修整です.
//  Read()もWrite()も処理したレコードサイズを返します.
//  フィルタがある場合も同様です.
//  それぞれのストリームのDataSizeの扱いですが,これは扱ったレコードサイズ
//  でなく扱ったファイルやソケットなどのサイズになります.レコードサイズと
//  一致するとは限りません.
//
//  Revision 1.3  2003/10/06 17:02:42  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2003/07/30 16:19:30  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TInputObjectSharedMemory.hh"
#include "TStreamableObject.hh"
#include "TInputObjectFilter.hh"
#include "TDataRecord.hh"
#include "TDataSection.hh"
#include "TDataSegment.hh"
#include "TDataElement.hh"

TInputObjectSharedMemory::TInputObjectSharedMemory( Tint memsize, Tint maxevt )
  : TObjectSharedMemory( memsize, maxevt ), 
    TInputObjectStream( tSharedMemoryStream ),
    theReadSuccessFlag( Tfalse )
{;}

TInputObjectSharedMemory::TInputObjectSharedMemory( TInputObjectFilter* filter, Tint memsize, Tint maxevt )
  : TObjectSharedMemory( memsize, maxevt ), 
    TInputObjectStream( filter, tSharedMemoryStream ),
    theReadSuccessFlag( Tfalse )
{;}

TInputObjectSharedMemory::~TInputObjectSharedMemory()
{;}

Tint TInputObjectSharedMemory::Read( TStreamableObject& object )
{
  if ( HasFilter() ) {
    return theObjectFilter -> Filtering( object, this );
  }


  theLastDataSize = theDataSize;
  theDataSize = 0;

  if ( IsReadable() == Tfalse ) {
    return theDataSize;
  }

  if ( theCurrentPositionOfMemorySpace == theMaxEvent - 1 ) {
    // return to top
    theAddress = theBaseAddress;
    theCurrentPositionOfMemorySpace = 0;
  }
    



  static Tobject_t objecttype = object.GetObjectType();

  Tvoid* begin = theAddress;

  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;
  }

  if ( theReadSuccessFlag == Tfalse ) {
    theAddress = begin;
    theDataSize = 0;
  }

  if ( theDataSize > 0 )
    theCurrentPositionOfMemorySpace ++;

  theTotalDataSize += theDataSize;
  return theDataSize;
}

TDataRecord TInputObjectSharedMemory::getDataRecord()
{
  Tint recsize;
  Tobject_t type;
  Tstring id;
  Tsize_t entries;
  TDataRecord record;
  readProperties( recsize, type, id, entries );
  if ( theReadSuccessFlag == Tfalse ) {
    return record;
  }
  record.SetID( id );
  record.SetObjectType( type );

  for ( Tsize_t i = 0; i < entries; i ++ ) {
    TDataSection section = getDataSection();
    if ( theReadSuccessFlag == Tfalse ) {
      break;
    } else {
      record.push_back( section );
    }
  }

  return record;
}

TDataSection TInputObjectSharedMemory::getDataSection()
{
  Tint recsize;
  Tobject_t type;
  Tstring id;
  Tsize_t entries;
  TDataSection section;
  readProperties( recsize, type, id, entries );
  if ( theReadSuccessFlag == Tfalse ) {
    return section;
  }
  section.SetID( id );
  section.SetObjectType( type );

  for ( Tsize_t i = 0; i < entries; i ++ ) {
    TDataSegment segment = getDataSegment();
    if ( theReadSuccessFlag == Tfalse ) {
      break;
    } else {
      section.push_back( segment );
    }
  }

  return section;
}

TDataSegment TInputObjectSharedMemory::getDataSegment()
{
  Tint recsize;
  Tobject_t type;
  Tstring id;
  Tsize_t entries;
  TDataSegment segment;
  readProperties( recsize, type, id, entries );
  if ( theReadSuccessFlag == Tfalse ) {
    return segment;
  }
  segment.SetID( id );
  segment.SetObjectType( type );

  for ( Tsize_t i = 0; i < entries; i ++ ) {
    TDataElement element = getDataElement();
    if ( theReadSuccessFlag == Tfalse ) {
      break;
    } else {
      segment.push_back( element );
    }
  }

  return segment;
}

TDataElement TInputObjectSharedMemory::getDataElement()
{
  Tint recsize;
  Tobject_t otype;
  Tstring id;
  Telement_t etype;
  Tint nprvs;
  TDataElement element;

  // read object type
  recsize = *( (Tint*)theAddress );
  theDataSize += Tsizeof( Tint );
  ( (Tint*)theAddress ) ++;


  // read object type
  otype = *( (Tobject_t*)theAddress );
  theDataSize += Tsizeof( Tobject_t );
  ( (Tobject_t*)theAddress ) ++;
  element.SetObjectType( otype );


  // read object ID
  Tsize_t nchar;
  Tchar* charbuf = 0;
  nchar = *( (Tsize_t*)theAddress );
  theDataSize += Tsizeof( Tsize_t );
  ( (Tsize_t*)theAddress ) ++;
  charbuf = new Tchar[ nchar ];
  for ( Tsize_t i = 0; i < nchar; i ++ ) {
    charbuf[ i ] = *( (Tchar*)theAddress );
    theDataSize += Tsizeof( Tchar );
    ( (Tchar*)theAddress ) ++;
  }
  id = charbuf;
  delete [] charbuf;
  element.SetID( id );


  // read element type
  etype = *( (Telement_t*)theAddress );
  theDataSize += Tsizeof( Telement_t );
  ( (Telement_t*)theAddress ) ++;
  element.SetElementType( etype );


  // read number of primitives
  nprvs = *( (Tint*)theAddress );
  theDataSize += Tsizeof( Tint );
  ( (Tint*)theAddress ) ++;
  element.SetNumberOfPrimitives( nprvs );


  if ( otype == tObjectUnknown || id == TunknownID || etype == tTypeUnknown || nprvs == 0 ) {
    theReadSuccessFlag = Tfalse;
    return element;
  }


  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;

  // read primitive data
  switch ( etype ) {

    case tTypeInt:
      ii = new Tint[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read int data
	ii[ i ] = *( (Tint*)theAddress );
	theDataSize += Tsizeof( Tint );
	( (Tint*)theAddress ) ++;
      }
      element.FillData( ii, nprvs );
      delete [] ii;
      break;


    case tTypeUnsignedInt:
      ui = new TUint[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read int data
	ui[ i ] = *( (TUint*)theAddress );
	theDataSize += Tsizeof( TUint );
	( (TUint*)theAddress ) ++;
      }
      element.FillData( ui, nprvs );
      delete [] ui;
      break;


    case tTypeWord:
    case tTypeUnsignedShort:
      us = new TUshort[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read ushort data
	us[ i ] = *( (TUshort*)theAddress );
	theDataSize += Tsizeof( TUshort );
	( (TUshort*)theAddress ) ++;
      }
      element.FillData( us, nprvs );
      delete [] us;
      break;

    case tTypeDouble:
      dd = new Tdouble[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read double data
	dd[ i ] = *( (Tdouble*)theAddress );
	theDataSize += Tsizeof( Tdouble );
	( (Tdouble*)theAddress ) ++;
      }
      element.FillData( dd, nprvs );
      delete [] dd;
      break;

    case tTypeFloat:
      ff = new Tfloat[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read double data
	ff[ i ] = *( (Tfloat*)theAddress );
	theDataSize += Tsizeof( Tfloat );
	( (Tfloat*)theAddress ) ++;
      }
      element.FillData( ff, nprvs );
      delete [] ff;
      break;

    case tTypeShort:
      ss = new Tshort[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read short data
	ss[ i ] = *( (Tshort*)theAddress );
	theDataSize += Tsizeof( Tshort );
	( (Tshort*)theAddress ) ++;
      }
      element.FillData( ss, nprvs );
      delete [] ss;
      break;

    case tTypeLong:
      ll = new Tlong[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read long data
	ll[ i ] = *( (Tlong*)theAddress );
	theDataSize += Tsizeof( Tlong );
	( (Tlong*)theAddress ) ++;
      }
      element.FillData( ll, nprvs );
      delete [] ll;
      break;

    case tTypeUnsignedLong:
      ul = new TUlong[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {
	// read long data
	ul[ i ] = *( (TUlong*)theAddress );
	theDataSize += Tsizeof( TUlong );
	( (TUlong*)theAddress ) ++;
      }
      element.FillData( ul, nprvs );
      delete [] ul;
      break;

    case tTypeString:
      strbuf = new Tstring[ nprvs ];
      for ( Tint i = 0; i < nprvs; i ++ ) {

	// read number of characters
	Tsize_t nchar;
	nchar = *( (Tsize_t*)theAddress );
	theDataSize += Tsizeof( Tsize_t );
	( (Tsize_t*)theAddress ) ++;

	// read string
	cc = new Tchar[ nchar ];
	for ( Tsize_t j = 0; j < nchar; j ++ ) {
	  cc[ j ] = *( (Tchar*)theAddress );
	  theDataSize += Tsizeof( Tchar );
	  ( (Tchar*)theAddress ) ++;
	}

	strbuf[ i ] = cc;
	delete [] cc;
      }
      element.FillData( strbuf, nprvs );
      delete [] strbuf;
      break;

    case tTypeUnknown:
    case tTypeObject:
    default:
      theReadSuccessFlag = Tfalse;
      return element;
  }

  return element;
}

Tvoid TInputObjectSharedMemory::readProperties( Tint& recsize, Tobject_t& type, Tstring& id, Tsize_t& entries )
{
  // read record size
  recsize = *( (Tint*)theAddress );
  theDataSize += Tsizeof( Tint );
  ( (Tint*)theAddress ) ++;


  // read object type
  type = *( (Tobject_t*)theAddress );
  theDataSize += Tsizeof( Tobject_t );
  ( (Tobject_t*)theAddress ) ++;


  // read object ID
  Tsize_t nchar;
  Tchar* charbuf = 0;
  nchar = *( (Tsize_t*)theAddress );
  theDataSize += Tsizeof( Tsize_t );
  ( (Tsize_t*)theAddress ) ++;
  charbuf = new Tchar[ nchar ];
  for ( Tsize_t i = 0; i < nchar; i ++ ) {
    charbuf[ i ] = *( (Tchar*)theAddress );
    theDataSize += Tsizeof( Tchar );
    ( (Tchar*)theAddress ) ++;
  }
  id = charbuf;
  delete [] charbuf;


  // read number of entries
  entries = *( (Tsize_t*)theAddress );
  theDataSize += Tsizeof( Tsize_t );
  ( (Tsize_t*)theAddress ) ++;


  if ( type == tObjectUnknown || id == TunknownID || entries == 0 ) {
    theReadSuccessFlag = Tfalse;
    return;
  }

  theReadSuccessFlag = Ttrue;

  return;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TInputObjectSharedMemory)
#endif
