// =====================================================================
//  $Id: TSoftwareAdcModule.cc,v 1.5 2004/03/07 10:30:31 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: TSoftwareAdcModule.cc,v $
//  Revision 1.5  2004/03/07 10:30:31  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.4  2004/03/01 05:35:29  goiwai
//  *** empty log message ***
//
//  Revision 1.3  2003/10/06 17:02:40  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2003/07/30 16:19:11  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TSoftwareAdcModule.hh"
#include "TDataSegment.hh"
#include "TDataElement.hh"

Tint TSoftwareAdcModule::theSeed = (Tint)time( 0 );
TRandomEngine TSoftwareAdcModule::theRandomEngine( (Tlong)(TSoftwareAdcModule::theSeed) );

TSoftwareAdcModule::TSoftwareAdcModule( Tint nchannel, Tint scale, Trandom_t randtype )
  : TSoftwareModule( nchannel ), theScale( scale ),
    theMean( nchannel, 0 ), theSigma( nchannel, 0 ), theChannel( nchannel, 0 ),
    theRandomType( randtype )
{
  setParameters();
  Update();
}

TSoftwareAdcModule::TSoftwareAdcModule( const TSoftwareAdcModule& right )
  : TSoftwareModule( right ), theMean( right.theMean ), 
    theSigma( right.theSigma ), theChannel( right.theChannel ),
    theRandomType( right.theRandomType )
{
  SetSeed( right.GetSeed() );
  SetRandomEngine( right.GetRandomEngine() );
}

TSoftwareAdcModule::~TSoftwareAdcModule()
{;}

Tint TSoftwareAdcModule::Clear()
{
  for ( Tint i = 0; i < theNumberOfChannels; i ++ ) {
    theChannel[ i ] = 0;
  }
  return theStatus = tStatusSuccess;
}

Tint TSoftwareAdcModule::Update()
{
  switch ( theRandomType ) {
    case tRandomLandau:
    case tRandomExponential:
    case tRandomGaussian:
    case tRandomChiSquare:
    case tRandomGamma:
    case tRandomPoisson:
    case tRandomUnknown:
    default:
      fillGaussian();
      break;
  }

  return theStatus;
}

Tint TSoftwareAdcModule::Initialize()
{
  Clear();
  for ( Tint i = 0; i < theNumberOfChannels; i ++ ) {
    theMean[ i ] = 0;
    theSigma[ i ] = 0;
  }
  setParameters();
  return theStatus = tStatusSuccess;
}

Tvoid TSoftwareAdcModule::FillData( TDataElement& element, Tint channel )
{
  if ( channel < 0 || channel >= theNumberOfChannels ) {
    Tcerr << "TSoftwareAdcModule::FillData: invalid ID " << channel << Tendl;
    theStatus = -EFAULT;
    element.FillData( &theStatus, tTypeInt, 1 );
  } else {
    element.FillData( &theChannel[ channel ], tTypeInt, 1 );
  }
  return;
}

const TSoftwareAdcModule& TSoftwareAdcModule::operator=( const TSoftwareAdcModule& right )
{
  *( (TSoftwareModule*)this ) = *( (TSoftwareModule*)(&right) );
  theMean = right.theMean;
  theSigma = right.theSigma;
  theChannel = right.theChannel;
  theRandomType = right.theRandomType;
  SetSeed( right.GetSeed() );
  SetRandomEngine( right.GetRandomEngine() );
  return *this;
}

Tbool TSoftwareAdcModule::operator==( const TSoftwareAdcModule& right ) const
{
  Tbool ret = Ttrue;
  ret &= ( *( (TSoftwareModule*)this ) == *( (TSoftwareModule*)(&right) ) );
  ret &= ( theMean == right.theMean );
  ret &= ( theSigma == right.theSigma );
  ret &= ( theChannel == right.theChannel );
  ret &= ( theRandomType == right.theRandomType );
  return ret;
}

Tbool TSoftwareAdcModule::operator!=( const TSoftwareAdcModule& right ) const
{
  Tbool ret = Tfalse;
  ret |= ( *( (TSoftwareModule*)this ) != *( (TSoftwareModule*)(&right) ) );
  ret |= ( theMean != right.theMean );
  ret |= ( theSigma != right.theSigma );
  ret |= ( theChannel != right.theChannel );
  ret |= ( theRandomType != right.theRandomType );
  return ret;
}

Tvoid TSoftwareAdcModule::setParameters()
{
  TRandomFlat randomFlat( TSoftwareAdcModule::theRandomEngine );

  for ( Tint i = 0; i < theNumberOfChannels; i ++ ) {
    theMean[ i ] = randomFlat.fireInt( theScale );
    Tdouble distance = (Tdouble)theMean[ i ];
    if ( (Tdouble)theScale / 2.0 < distance )
      distance = theScale - distance;

    // 3sigma = 0.997
    theSigma[ i ] = randomFlat.fireInt( (Tint)( distance / 3.0 ) );
  }

  return;
}

Tvoid TSoftwareAdcModule::fillGaussian()
{
  TRandomGaussian randomGaussian( TSoftwareAdcModule::theRandomEngine );
  for ( Tint i = 0; i < theNumberOfChannels; i ++ ) {
    Tint idata = (Tint)( randomGaussian.fire( (Tdouble)theMean[ i ], (Tdouble)theSigma[ i ] ) );
    if ( idata > theScale || idata < 0 ) {
      idata = tDataOverFlow;
      theStatus = -EFAULT;
    }
    theChannel[ i ] = idata;
  }
  return;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TSoftwareAdcModule)
#endif
