/*
$Id: EventDataToHistogramBase.cc 2110 2010-04-07 04:35:47Z jisuzuki $
 */

#include "EventDataToHistogramBase.hh"

//////////////////////////////////////////////////////////////////////
EventDataToHistogramBase::
EventDataToHistogramBase( UInt4 _NumOfPsd, UInt4 _NumOfPixel ){
  Allocate( _NumOfPsd, _NumOfPixel );
  _CrateId =  _ModuleId = _psd_num = _ph_l = _ph_r = _tof = 0;
  _PulseId = 0;
  _k = _t1 = _t2 = _t3 = _t4 = _t5 = 0;
  _t6 = 0.0;
  Range = NULL;
  CheckFlag = 0;
}
//////////////////////////////////////////////////////////////////////
EventDataToHistogramBase::
EventDataToHistogramBase(){
  _CrateId =  _ModuleId = _psd_num = _ph_l = _ph_r = _tof = 0;
  _PulseId = 0;
  _k = _t1 = _t2 = _t3 = _t4 = _t5 = 0;
  _t6 = 0.0;
  Range = NULL;
  CheckFlag = 0;
}
//////////////////////////////////////////////////////////////////////
EventDataToHistogramBase::
~EventDataToHistogramBase(){
  delete a;
  delete b;
  delete c;
  for( UInt4 i=0; i<NumOfPixel; i++ ){
    delete ( *gslhist )[ i ];
  }
  delete gslhist;
  delete [] Range;
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
Allocate(UInt4 _NumOfPsd, UInt4 _NumOfPixel ){

  CurrentPulseId = StartPulseId = EndPulseId = 0LL;
  NumOfPsd   = _NumOfPsd;
  NumOfPixel = _NumOfPixel;
  a = new std::vector<Double>( NumOfPsd );
  b = new std::vector<Double>( NumOfPsd );
  c = new std::vector<Double>( NumOfPsd );
  for( UInt4 i=0; i<NumOfPsd; i++ ){
    ( *a )[ i ] = 1.0;
    ( *b )[ i ] = 1.0;
    ( *c )[ i ] = 1.0;
  }

  gslhist = new std::vector<GslHistogram*>( NumOfPixel );
  for( UInt4 i=0; i<NumOfPixel; i++ ){
    ( *gslhist )[ i ] = NULL;
  }
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
SetPsdParam( UInt4 PsdId, Double A, Double B, Double C ){
  ( *a )[ PsdId ] = A;
  ( *b )[ PsdId ] = B;
  ( *c )[ PsdId ] = C;
}
//////////////////////////////////////////////////////////////////////
UInt4 EventDataToHistogramBase::
PutPixelPosition( UInt4 PsdId, UInt4 pl, UInt4 pr ){
  return (UInt4) ( ( *a )[ PsdId ] * (Double)pr
    / ( (Double)pl + ( *b )[ PsdId ] * (Double)pr )
    - ( *c )[ PsdId ] );
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
SetTofBin( UInt4 PixelId, Double *tof, UInt4 Size ){

#ifdef MULTH
  GslHistogram *gs = new GslHistogram( tof, Size, MULTH );
#else
  GslHistogram *gs = new GslHistogram( tof, Size );
#endif
  ( *gslhist )[ PixelId ] = gs;
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
SetTofBin( UInt4 PixelId, std::vector<Double> tof ){

  Range = new Double [ tof.size() ];
  for( UInt4 i=0; i<tof.size(); i++ ){
    Range[i] = tof[i];
  }
  SetTofBin( PixelId, Range, (UInt4)(tof.size()) );

}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
SetTofBin_DeltaT_Const( UInt4 PixelId,
                        Double Ini, Double Fin,
                        Double DeltaT ){
  std::vector<Double> bin;
  Double Current = Ini;
  while( Current <= Fin ){
    bin.push_back( Current );
    Current = Current + DeltaT;
  }

  Range = new Double [ bin.size() ];
  for( UInt4 i=0; i<bin.size(); i++ ){
    Range[i] = bin[i];
  }
  SetTofBin( PixelId, Range, (UInt4)(bin.size()) );
  //SetTofBin( PixelId, bin );
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
SetTofBin_DeltaToverT_Const( UInt4 PixelId,
                             Double Ini, Double Fin,
                             Double DeltaToverT ){
  std::vector<Double> bin;
  Double Current = Ini;
  while( Current <= Fin ){
    bin.push_back( Current );
    Current = Current * ( ( DeltaToverT + 2.0 ) / ( 2.0 - DeltaToverT ) );
  }
  Range = new Double [ bin.size() ];
  for( UInt4 i=0; i<bin.size(); i++ ){
    Range[i] = bin[i];
  }
  SetTofBin( PixelId, Range, (UInt4)(bin.size()) );
  //SetTofBin( PixelId, bin );
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
Increment( UInt4 Channel, UChar* data, UInt4 size ){

  UChar *CopyData = new UChar [ size * 8 ];
  for( UInt4 i=0; i<size*8; i++ ){
    CopyData[i] = data[i];
  }

  UInt4 index = 0;
  for( UInt4 i=0; i<size; i++ ){

    // 0x5a --- event data      = 90
    // 0x5b --- T0 data         = 91
    // 0x5c --- time stamp data = 92

    index = i * 8;

    if( *(data+index) == 90 && CheckFlag==1 ){ // event data
        Decode_EventData( CopyData+index, &_psd_num, &_k, &_ph_l, &_ph_r, &_tof );
        UInt4 psd_id = PutPsdId( Channel, _ModuleId, _psd_num );
        UInt4 pixel_id = PutPixelId( psd_id, PutPixelPosition( psd_id, _ph_l, _ph_r  ) );
        ( ( *gslhist )[ pixel_id ] ) -> Increment( ClockToMicrosec( _tof )*TimeFocParamC1( pixel_id )
                                                   + TimeFocParamC0( pixel_id ) );
        // TimeFocParamC1( pixel_id ) and TimeFocParamC0( pixel_id ) defined in this class
        // return time-focusing parameters, and their return value are 1.0 and 0.0, respectively.
        // If you want to change their default return values, the functions should be
        // overridden in the child class of this class.
    }
    else if( *(data+index) == 91 ){ // T0 data
      CheckFlag = 1;
      Decode_T0Data( CopyData+index, &_CrateId, &_ModuleId, &_PulseId );
    }
    else if( *(data+index) == 92 ){ // time stamp data
      Decode_TimeStampData( CopyData+index, &_t1, &_t2, &_t3, &_t4, &_t5, &_t6 );
    }
  }
  delete [] CopyData;
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
Reset(){
  for( UInt4 i=0; i<NumOfPixel; i++ ){
    ( *gslhist )[ i ] -> Reset();
  }
}
//////////////////////////////////////////////////////////////////////
Double EventDataToHistogramBase::
ClockToMicrosec( UInt4 Clock ){
  return (double)Clock * 0.025;
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
Decode_T0Data( const UChar *data, UInt4 *CrateId, UInt4 *ModuleId,
               UInt8 *PulseId ){
  *CrateId =  (UInt4)( *(data+1) );
  *ModuleId = (UInt4)( *(data+2) );
  *PulseId =  (UInt8)( (UInt8)( *(data+3) )  * (UInt8)(256 * 256) * (UInt8)(256 * 256) +
                       (UInt8)( *(data+4) )  * (UInt8)(256 * 256 * 256) +
                       (UInt8)( *(data+5) )  * (UInt8)(256 * 256) +
                       (UInt8)( *(data+6) )  * (UInt8)(256) +
                       (UInt8)( *(data+7) ) );

  /*
  *PulseId = (UInt8)( ( *(data+3) ) * 256 * 256 * 256 * 256 +
                      ( *(data+4) ) * 256 * 256 * 256 +
                      ( *(data+5) ) * 256 * 256 +
                      ( *(data+6) ) * 256 +
                      ( *(data+7) ) );
  */

  /*
  *CrateId = (UInt4)( *(data+3) );
  *ModuleId = (UInt4)( *(data+4) );
  *PulseId = (UInt8)(( *(data+5) ) * 256 * 256 +
    ( *(data+6) ) * 256 +
    ( *(data+7) ));
  */
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
Decode_EventData( const UChar *data, UInt4 *psd_num, UInt4 *k,
                  UInt4 *ph_l, UInt4 *ph_r, UInt4 *tof ){
  //*psd_num = (UInt4)( *(data+1) & 0x7 );
  *psd_num = (UInt4)( *(data+4) & 0x7 );
  *k = (UInt4)( *(data+6) )/16;
  *ph_l = (UInt4)( *(data+5) ) * 16 + ( *k );
  *ph_r = (UInt4)( *(data+7) )
    + 256 * ( (UInt4( *(data+6) ) )-(*k)*16 );
  /*
  *tof = (UInt4)( *(data+2) << 16 )
    + (UInt4)( *(data+3) << 8 )
    + (UInt4)( *(data+4) );
  */
  *tof = (UInt4)( *(data+1) << 16 )
    + (UInt4)( *(data+2) << 8 )
    + (UInt4)( *(data+3) );
}
//////////////////////////////////////////////////////////////////////
void EventDataToHistogramBase::
Decode_TimeStampData( const UChar *data, UInt4 *t1, UInt4 *t2, UInt4 *t3,
                      UInt4 *t4, UInt4 *t5, Double *t6 ){
  *t1 = (UInt4)( *(data+1) );
  *t2 = (UInt4)( *(data+2) );
  *t3 = (UInt4)( *(data+3) );
  *t4 = (UInt4)( *(data+4) );
  *t5 = (UInt4)( *(data+5) );
  *t6 = (Double)( *(data+6) ) + (Double)( *(data+7) ) / 256.0;
}
//////////////////////////////////////////////////////////////////////
ElementContainerMatrix EventDataToHistogramBase::
PutElementContainerMatrix( std::vector<UInt4> NumObElements ){
  ElementContainerMatrix M;
  UInt4 Num = 0;
  for( UInt4 i=0; i<NumObElements.size(); i++ ){ Num=Num+NumObElements[i];}
  if( Num != NumOfPixel ){
    std::cerr << "The sum of NumObElements should be equal to NumOfPixel" << std::endl;
    std::cerr << "This method returns empty data container." << std::endl;
    return M;
  }

  Num = 0;
  for( UInt4 i=0; i<NumOfPsd; i++ ){
    ElementContainerArray a;
    for( UInt4 j=0; j<NumObElements[i]; j++ ){
      ElementContainer e;
      e.Add( "Counts", PutHist( Num ) );
      e.Add( "Tof", PutBin( Num ) );
      e.Add( "Errors", PutGslHistogram( Num )->PutHistogramErr() );
      a.Add( e );
      Num++;
    }
    M.Add( a );
  }
  return M;
}
//////////////////////////////////////////////////////////////////////
ElementContainerMatrix * EventDataToHistogramBase::
PutElementContainerMatrixP( std::vector<UInt4> NumObElements ){
  ElementContainerMatrix *M = new ElementContainerMatrix();
  UInt4 Num = 0;
  for( UInt4 i=0; i<NumObElements.size(); i++ ){ Num=Num+NumObElements[i];}
  if( Num != NumOfPixel ){
    std::cerr << "The sum of NumObElements should be equal to NumOfPixel" << std::endl;
    std::cerr << "This method returns empty data container." << std::endl;
    return M;
  }

  Num = 0;
  for( UInt4 i=0; i<NumOfPsd; i++ ){
    ElementContainerArray *a = new ElementContainerArray();
    for( UInt4 j=0; j<NumObElements[i]; j++ ){
      ElementContainer e;
      e.Add( "Counts", PutHist( Num ) );
      e.Add( "Tof", PutBin( Num ) );
      e.Add( "Errors", PutGslHistogram( Num )->PutHistogramErr() );
      a->Add( e );
      Num++;
    }
    M->AddPointer( a );
  }
  return M;
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
