////////////////////////////////////////////////////////////////
//
//  MFadc
//
//  
#include "MFadc.hxx"

#include "MMcEvt.hxx"

#include "TROOT.h"
#include <TApplication.h>
#include <TVirtualX.h>
#include <TGClient.h>

#include "TH1.h"
#include "TObjArray.h"

#include "MGFadcSignal.hxx"

using namespace std;

MFadc::MFadc(Int_t pix, Int_t shape, Float_t integral, Float_t fwhm, 
	     Int_t shapeout, Float_t integralout, Float_t fwhmout, 
	     Float_t trigger_delay, Float_t fadc_slices_per_ns,
	     Int_t fadc_slices_written, Int_t gainswitchamp,
	     Int_t shiftfromswitch2lowgain, Float_t hi2logainpeak) {
  //
  //  Constructor overloaded II 
  //  
  //  Input variables:
  //  1. integral(out) = integration of the single phe response for inner 
  // (outer) pixels.
  //  2. fwhm(out) = width at half high of the single phe response for
  // inner (outer) pixels.
  //
  // trigger_delay: shift of signals towards later times in FADC, in order
  // to center the signals in a good range. It acts as a sort of delay of 
  // the signals (before being sent to the FADC) with respect to the trigger.
  //
  //  The procedure is the following: 
  //  1. some parameters of the trigger are set to default.   
  //     this parameters of the trigger may be changed
  //  3. Then the all signals are set to zero

  numpix=pix;
  
  fwhm_resp = fwhm; 
  integ_resp = integral; 
  fwhm_resp_outer = fwhmout; 
  integ_resp_outer = integralout; 
  shape_resp = shape;
  shape_resp_outer = shapeout;
  fFadcSlicesPerNanosec = fadc_slices_per_ns;
  fFadcSlices = fadc_slices_written;
  fGainSwitchAmp = gainswitchamp;
  fShiftFromSwitch2LowGain = shiftfromswitch2lowgain;
  fHi2LoGainPeak = hi2logainpeak;

  fSlices_mFadc = (Int_t)(TOTAL_TRIGGER_TIME*fFadcSlicesPerNanosec);

  for (Int_t i = 0; i < CAMERA_PIXELS; i++)
    {
      sig[i] = new Float_t[fSlices_mFadc];
      sig_LG[i] = new Float_t[fSlices_mFadc];
    }

  noise = new Float_t[fSlices_mFadc*1001];
  noise_outer = new Float_t[fSlices_mFadc*1001];
  digital_noise = new Float_t[fSlices_mFadc*1001];

  for (Int_t i = 0; i < CAMERA_PIXELS; i++)
    {
      output[i] = new Float_t[fFadcSlices];
      output_lowgain[i] = new Float_t[fFadcSlices];
    }

  cout<< "[MFadc]  Setting up the MFadc with this values "<< endl ; 
  cout<< "[MFadc]  FADC sampling frequency: " << fFadcSlicesPerNanosec << " GHz" << endl ; 
  cout<< "[MFadc]    - Inner pixels :  "<< endl ; 

  switch(shape_resp){
  case 0:
    cout<< "[MFadc]       Pulse shape   : Gaussian ("<<shape_resp<<")"<< endl ; 
    cout<< "[MFadc]       Response Area : "<<integ_resp<<" adc counts"<< endl ; 
    cout<< "[MFadc]       Response FWHM : "<<fwhm_resp<<" ns"<< endl ; 
    break;
  case 1:
    cout<< "[MFadc]       Pulse shape   : From Pulpo ("<<shape_resp<<")"<< endl ; 
    cout<< "[MFadc]       Response Area : "<<integ_resp<<" adc counts"<< endl ; 
    break;
  default:
    cout<< "[MFadc]       Pulse shape unknown"<<endl;
  }
  cout<< "[MFadc]    - Outer pixels :  "<< endl ; 
  switch(shape_resp_outer){
  case 0:
    cout<< "[MFadc]       Pulse shape   : Gaussian ("<<shape_resp_outer<<")"<<endl; 
    cout<< "[MFadc]       Response Area : "<<integ_resp_outer<<" adc counts"<<endl; 
    cout<< "[MFadc]       Response FWHM : "<<fwhm_resp_outer<<" ns"<< endl ; 
    break;
  case 1:
    cout<< "[MFadc]       Pulse shape   : From Pulpo ("<<shape_resp_outer<<")"<<endl;
    cout<< "[MFadc]       Response Area : "<<integ_resp_outer<<" adc counts"<< endl ;
    break;
  default:
    cout<< "[MFadc]       Pulse shape unknown ("<<shape_resp_outer<<")"<<endl;
  }

  
  //
  // set up the response shape
  // 

  //
  // First select number of bins for the histogram which will contain the single 
  // photoelectron response of the FADC. The width of these bins is smaller than that 
  // of the real FADC slices by a factor SUBBINS (see MFadcDefine.h):
  //
  if (shape_resp == 1)
    fResponseSlicesFadc = (Int_t)(50.*fFadcSlicesPerNanosec*SUBBINS); 
  // 50 ns range

  else
    fResponseSlicesFadc = (Int_t)(7*fwhm_resp/2.35*fFadcSlicesPerNanosec*SUBBINS); 
  // 7 sigma range

  sing_resp = new Float_t[fResponseSlicesFadc];
  sing_resp_outer = new Float_t[fResponseSlicesFadc];

  sing_resp_lowgain = new Float_t[fResponseSlicesFadc];
  sing_resp_outer_lowgain = new Float_t[fResponseSlicesFadc];


  // Parameters for real pulse shaped as measured with the Pulpo device:
  fPulseParameters[0] = 2.066; 
  fPulseParameters[1] = 1.568; 
  fPulseParameters[2] = 3; // This will set the peak of the pulse at x ~ 3*3.3 = 10 ns
                           // It is just a safe value so that the pulse is well contained.
  fPulseParameters[3] = 0.00282; 
  fPulseParameters[4] = 0.04093; 
  fPulseParameters[5] = 0.2411; 
  fPulseParameters[6] = -0.009442;

  // Now for the low gain:
  fPulseParametersLG[0] = 6.88031e-01;
  fPulseParametersLG[1] = 1.19492e+00;
  fPulseParametersLG[2] = 3.; // Same as above
  fPulseParametersLG[3] = 8.10590e-03;
  fPulseParametersLG[4] = 1.92851e-01;
  fPulseParametersLG[5] = 3.30315e-01;
  fPulseParametersLG[6] = 1.12980e-03;

  Int_t  i ;
  
  Float_t   sigma ; 
  Float_t   x, x0 ; 
  Float_t   dX, dX2 ; 

  Float_t   response_sum_inner, response_sum_outer;
  Float_t   response_sum_inner_LG, response_sum_outer_LG;

  response_sum_inner = 0.;
  response_sum_outer = 0.;
  response_sum_inner_LG = 0.;
  response_sum_outer_LG = 0.;

  dX  = 1. / fFadcSlicesPerNanosec / SUBBINS ;   // Units: ns
  dX2 = dX/2. ; 

  switch(shape_resp){

  case 0:
    sigma = fwhm_resp / 2.35 ; 
    x0 = 3*sigma;
    fadc_time_offset = trigger_delay-x0; // ns

    for (i = 0; i < fResponseSlicesFadc ; i++ ) 
      {  
	x = i * dX + dX2 ; 
      
	sing_resp[i] = (Float_t)(expf(-0.5*(x-x0)*(x-x0)/(sigma*sigma))); 
	sing_resp_lowgain[i] = sing_resp[i]; 

	// Use the same pulse for high and low gain in case of gaussian shape
	// FIXME: it would be nice to be able to choose a different shape for 
	// high and low gain:
	response_sum_inner += sing_resp[i];
	response_sum_inner_LG += sing_resp_lowgain[i];
      }

    break;
  case 1:
    float p0,p1,p2,p3,p4,p5,p6;
    float d;
    float zed_slices;
    // Parameters values extracted from fitting a real FADC response
    // gaussian electronic pulse passed through the whole chain from 
    // transmitter boards to FADC.
    p0 = fPulseParameters[0];
    p1 = fPulseParameters[1];
    p2 = fPulseParameters[2];
    p3 = fPulseParameters[3];
    p4 = fPulseParameters[4];
    p5 = fPulseParameters[5];
    p6 = fPulseParameters[6];

    float p0_LG, p1_LG, p2_LG, p3_LG, p4_LG, p5_LG, p6_LG;
    p0_LG = fPulseParametersLG[0];
    p1_LG = fPulseParametersLG[1];
    p2_LG = fPulseParametersLG[2];
    p3_LG = fPulseParametersLG[3];
    p4_LG = fPulseParametersLG[4];
    p5_LG = fPulseParametersLG[5];
    p6_LG = fPulseParametersLG[6];

    p2_LG += (fHi2LoGainPeak - fFadcSlices); // Adjust distance between high and low gain peaks


    // Now define the time before trigger to read FADC signal when it
    // has to be written. Here FADC_SLICES_PER_NSEC (=0.3) is the value
    // for the 300 MHz MAGIC FADCs and must NOT be changed, even if you
    // use a faster sampling in the simulation (through the input card 
    // command "fadc_GHz"), because this is just a conversion of units. The
    // parameters of the "pulpo" pulse shape were obtained with the 300 MHz
    // FADC and so we convert the time parameter to units of 3.3 ns slices 
    // just to use the provided parametrization, and no matter what sampling 
    // frequency we are simulating!

    fadc_time_offset = trigger_delay - p2 / FADC_SLICES_PER_NSEC; // ns


    for (i=0; i< fResponseSlicesFadc ; i++ )
      {
	x = i * dX + dX2;

	// x has to be converted from ns to units FADC slices of the default 
	// FADC of 300 MHz (these are just units, and must be these even if you
	// are using another sampling frequency!):
	//
	zed_slices = x * FADC_SLICES_PER_NSEC - p2;
	d = (zed_slices>0)? 0.5 : -0.5;

	sing_resp[i] =  (Float_t) (p0*exp(-p1*(exp(-p1*zed_slices)+zed_slices))+
				   p3+p4*exp(-p1*(exp(-p1*zed_slices)+
						  p5*zed_slices))+p6*d);
	response_sum_inner += sing_resp[i];


	// Now the low gain:

	zed_slices = x * FADC_SLICES_PER_NSEC - p2_LG;
	d = (zed_slices>0)? 0.5 : -0.5;

	sing_resp_lowgain[i] =  (Float_t) (p0_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+zed_slices))+
					   p3_LG+p4_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+
							  p5_LG*zed_slices))+p6_LG*d);
	response_sum_inner_LG += sing_resp_lowgain[i];

      }

    break;
  default:
    cout<<"[MFadc] MFadc::MFadc : Shape of FADC pulse for inner pixel unknown."
	<<endl;
    cout<<"[MFadc] MFadc::MFadc : Exiting Camera ..."
	<<endl;
    exit(1);
  } 

  // Response for outer pixels

  switch(shape_resp_outer){

  case 0:
    sigma = fwhm_resp_outer / 2.35 ; 
    x0 = 3*sigma ; 
    
    for (i = 0; i < fResponseSlicesFadc ; i++ ) 
      {  
	x = i * dX + dX2 ; 
      
	//
	//   the value 1/sqrt(2*Pi*sigma^2) was introduced to normalize 
	//   the area at the input value After this, the integral
	//   of the response will be integ_resp.
	//
	sing_resp_outer[i] = (Float_t) (expf(-0.5 * (x-x0)*(x-x0) / 
					     (sigma*sigma)) ) ; 
	response_sum_outer += sing_resp_outer[i];
      } 
    break;
  case 1:
    float p0,p1,p2,p3,p4,p5,p6;
    float d;
    float zed_slices;
    // Parameters values extracted from fitting a real FADC response
    // gaussian electronic pulse passed through the whole chain from 
    // transmitter boards to FADC.

    p0 = fPulseParameters[0];
    p1 = fPulseParameters[1];
    p2 = fPulseParameters[2];
    p3 = fPulseParameters[3];
    p4 = fPulseParameters[4];
    p5 = fPulseParameters[5];
    p6 = fPulseParameters[6];

    float p0_LG, p1_LG, p2_LG, p3_LG, p4_LG, p5_LG, p6_LG;
    p0_LG = fPulseParametersLG[0];
    p1_LG = fPulseParametersLG[1];
    p2_LG = fPulseParametersLG[2];
    p3_LG = fPulseParametersLG[3];
    p4_LG = fPulseParametersLG[4];
    p5_LG = fPulseParametersLG[5];
    p6_LG = fPulseParametersLG[6];

    p2_LG += (fHi2LoGainPeak - fFadcSlices); // Adjust distance between high and low gain peaks

    for (i=0; i< fResponseSlicesFadc ; i++ )
      {
	x = i * dX + dX2;

	// x has to be converted from ns to units FADC slices of the default 
	// FADC of 300 MHz (these are just units, and must be these even if you
	// are using another sampling frequency!):
	//
	zed_slices = x * FADC_SLICES_PER_NSEC - p2;
	d = (zed_slices>0)? 0.5 : -0.5;

	sing_resp_outer[i] = (Float_t) (p0*exp(-p1*(exp(-p1*zed_slices)+
						    zed_slices))+p3+
					p4*exp(-p1*(exp(-p1*zed_slices)+
						    p5*zed_slices))+p6*d);
	response_sum_outer += sing_resp_outer[i];


	// Now the low gain:

	zed_slices = x * FADC_SLICES_PER_NSEC - p2_LG;
	d = (zed_slices>0)? 0.5 : -0.5;

	sing_resp_outer_lowgain[i] =  (Float_t) (p0_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+zed_slices))+
						 p3_LG+p4_LG*exp(-p1_LG*(exp(-p1_LG*zed_slices)+
								   p5_LG*zed_slices))+p6_LG*d);
	response_sum_outer_LG += sing_resp_outer_lowgain[i];
      }
    break;
  default:
    cout<<"[MFadc] MFadc::MFadc : Shape of FADC pulse for inner pixel unknown."
	<<endl;
    cout<<"[MFadc] MFadc::MFadc : Exiting Camera ..."
	<<endl;
    exit(1);
  }

  //   
  // Normalize responses to values set through input card: (= set gain of electronic chain)
  // Take into account that only 1 of every SUBBINS bins of sing_resp[] will be "sampled" by 
  // the FADC, so we have to correct for this to get the right "FADC integral" (=integ_resp) 
  // per photoelectron:
  //

  for (i = 0; i < fResponseSlicesFadc ; i++ )
    {  
      sing_resp[i] *= integ_resp / response_sum_inner * SUBBINS;
      sing_resp_outer[i] *= integ_resp_outer / response_sum_outer * SUBBINS;

      // The low gain will be further scaled down later; for now we normalize it with to same
      // integral as the high gain.
      sing_resp_lowgain[i] *= integ_resp / response_sum_inner_LG * SUBBINS;
      sing_resp_outer_lowgain[i] *= integ_resp_outer / response_sum_outer_LG * SUBBINS;
    }

  //
  // init the Random Generator for Electronic Noise
  //

  GenElec = new TRandom () ; 

  Reset();

  //
  //  set all pedestals to 0
  //
  
  for ( i =0 ; i <CAMERA_PIXELS ; i++ ) { 
    pedestal[i] = 0.0 ; 
  }

  cout<<" end of MFadc::MFadc()"<<endl;
}
  
void MFadc::Reset() { 
    //
    //  set all values of the signals to zero
    //  set the values of FADC slices that would be read after trigger to zero
    //
    memset(used, 0, CAMERA_PIXELS*sizeof(Bool_t));

    for (Int_t i = 0; i < CAMERA_PIXELS; i++)
      {
	memset(output[i], 0, fFadcSlices*sizeof(Float_t));
	memset(output_lowgain[i], 0, fFadcSlices*sizeof(Float_t));
      }

    // 
    
    //
    for (Int_t i = 0; i < CAMERA_PIXELS; i++)
      {
	memset(sig[i], 0, (Int_t)(fSlices_mFadc*sizeof(Float_t)));    // Added 15 01 2004, AM
	memset(sig_LG[i], 0, (Int_t)(fSlices_mFadc*sizeof(Float_t))); // Added 01 03 2005, AM
      }
}
void MFadc::Fill( Int_t iPix, Float_t time, 
		  Float_t amplitude, Int_t isinner ) { 

    // AM, Jan 2004 : added delay to shift the signal peak to the desired
    // range in the FADC window (indicated through the trigger_delay command
    // in the camera input card.

  time += fadc_time_offset;

  if(isinner)
    Fill(iPix, time, amplitude);
  else
    FillOuter(iPix, time, amplitude);

}
void MFadc::Fill( Int_t iPix, Float_t time, Float_t amplitude ) { 
  
  //
  // fills the information about one single Phe in the Trigger class
  //
  // Parameters are the number of the pixel and the time-difference to the
  // first photon.
  //
  //
  // AM, Jan 2004: Replaced former FADC simulation (integration of signal)
  // with a more realistic one (measuring signal height at discrete points).
  //


  Int_t i, ichan, ichanfadc ; 
  
  //
  //   first we have to check if the pixel iPix is used or not until now
  //   if this is the first use, reset all signal for that pixel
  // 
  if ( iPix > numpix ) 
    {
      cout << " WARNING: MFadc::Fill() : iPix greater than Pixels in Camera = "
	   << numpix
	   << endl;
      exit(987); 
    }

  if ( used[iPix] == FALSE ) 
    {
      used [iPix] = TRUE; 
    
      for (i=0; i < (Int_t) fSlices_mFadc; i++ )
	{
	  sig[iPix][i] = 0.;
	  sig_LG[iPix][i] = 0.;
	}
    }

  //
  //   then select the time slice to use (ichan) 
  // 

  if ( time < TOTAL_TRIGGER_TIME+fadc_time_offset ) { 
    //
    // Convert time into units of the width of the analog 
    // signal histogram, sing_resp:
    //
    ichan = (Int_t) ( time * fFadcSlicesPerNanosec * SUBBINS); 

    //
    //   putting the response slices in the right sig slices.
    //   Be careful, because both slices have different widths. 
    //

    // We want to put the single phe response given by sing_resp into the
    // array sig[][], but only one of each SUBBINS bins, since the binning 
    // of sing_resp is finer than that of sig[][]. We want that the start of
    // sing_resp coincides with the time "time" with respect to the begining
    // of sig[][]

    // We take the pulse height in the middle of FADC slices, we start in the
    // first such point after the time "time" (=ichan in response bins). Each
    // FADC slice corresponds to SUBBINS response bins.

    Int_t first_i =  Int_t(SUBBINS/2) - ichan%(Int_t)SUBBINS;
    first_i = first_i < 0 ? (Int_t)SUBBINS+first_i : first_i;    //
    //
    // first_i is the first bin of sing_resp which matches the center of one
    // bin of sig[][]
    //

    for ( i = first_i ; i < (Int_t)fResponseSlicesFadc; i += (Int_t)SUBBINS)
      {	
	ichanfadc = (Int_t) ((ichan+i)/SUBBINS) ; 
	if ( ichanfadc < 0 )
	  continue;

	//
	// fSlices_mFadc is by default 48. sig[][] is not the final FADC output; that 
	// will be later filled (from sig[][]) in MFadc::TriggeredFadc()
	//
	if ( (ichanfadc) < (Int_t) fSlices_mFadc )
	  {
	    sig[iPix][ichanfadc] += (amplitude * sing_resp[i] ); 
	    sig_LG[iPix][ichanfadc] += (amplitude * sing_resp_lowgain[i] );
	  }
      }
  }
  else
    cout << "  WARNING!  Fadc::Fill " << time << "  out of TriggerTimeRange " 
	 << TOTAL_TRIGGER_TIME+fadc_time_offset << endl ; 

}

void MFadc::FillOuter( Int_t iPix, Float_t time, Float_t amplitude ) { 
  
  //
  // fills the information about one single Phe in the Trigger class
  // for an outer pixel
  //
  // See explanations of the code in function Fill() above 
  //

  Int_t i, ichan, ichanfadc ; 
  
  if ( iPix > numpix ) 
    {
      cout << " WARNING: MFadc::FillOuter() : iPix greater than CAMERA_PIXELS"
	   << endl ;
      exit(987) ; 
    }

  if ( used[iPix] == FALSE ) 
    {
      used [iPix] = TRUE ; 
    
      for (i=0; i < (Int_t) fSlices_mFadc; i++)
	{
	  sig[iPix][i] = 0.;
	  sig_LG[iPix][i] = 0.;
	}
    }


  if ( time < TOTAL_TRIGGER_TIME+fadc_time_offset ) { 

    ichan = (Int_t) ( time * fFadcSlicesPerNanosec * SUBBINS); 

    Int_t first_i =  Int_t(SUBBINS/2) - ichan%(Int_t)SUBBINS;
    first_i = first_i < 0 ? (Int_t)SUBBINS+first_i : first_i;

    for ( i = first_i ; i < (Int_t)fResponseSlicesFadc; i += (Int_t)SUBBINS)
      {
	ichanfadc = (Int_t) ((ichan+i)/SUBBINS); 

	if ( ichanfadc < 0 )
	  continue;

	if ( (ichanfadc) < (Int_t)fSlices_mFadc )
	  {
	    sig[iPix][ichanfadc] += (amplitude * sing_resp_outer[i] );
	    sig_LG[iPix][ichanfadc] += (amplitude * sing_resp_outer_lowgain[i] );
	  }

      }
    
  }
  else {
    cout << "  WARNING!  Fadc::FillOuter " << time << "  out of TriggerTimeRange " 
	 << TOTAL_TRIGGER_TIME+fadc_time_offset << endl ; 
  }
  
}

void MFadc::AddSignal( Int_t iPix, Float_t *resp) { 
  
  //
  // Adds signals to the fadc reponse from a given array
  // Parameters are the number of the pixel and the values to be added
  // With add the signal equally to the high and low gain branch. The low
  // gain branch is not yet scaled down!!
  //

  Int_t i ; 
  
  //
  //   first we have to check if the pixel iPix is used or not until now
  //   if this is the first use, reset all signal for that pixels
  // 
  if ( iPix > numpix ) 
    {
      cout << " WARNING:  MFadc::Fill() :  iPix greater than CAMERA_PIXELS"
	   << endl ;
      exit(987) ; 
    }

  if ( used[iPix] == FALSE ) 
    {
      used [iPix] = TRUE ; 
    
      for (i=0; i < (Int_t)fSlices_mFadc; i++ )
	{
	  sig[iPix][i] = 0. ; 
	  sig_LG[iPix][i] = 0. ; 
	}
    }
  for ( i = 0 ; i<(Int_t)fSlices_mFadc; i++ ) 
    {
      sig[iPix][i] += resp[i] ; 
      sig_LG[iPix][i] += resp[i] ; 
    }

}

void MFadc::SetPedestals( Int_t ped) { 
  //  It sets pedestal for each pixel flat randomly dstributed between 0 and ped
  //  It uses the instance of TRandom GenElec.

  Int_t i;

  for(i=0;i<numpix;i++){
    pedestal[i]= (Float_t)(ped* GenElec->Rndm());
  }
}

void MFadc::SetPedestals(  Float_t *ped) { 
  //  It sets pedestal for each pixel from ped array

  Int_t i;

  for(i=0;i<numpix;i++){
    pedestal[i]= ped[i];
  }
}


void MFadc::Pedestals(){
  // 
  //  It shifts the FADC contents their pedestal values
  //  It shifts the values in the analog signal, 
  //  therefore it has to be done before getting FADC output
  //

  Int_t i, j;

  for(i=0;i<numpix;i++)
    for(j=0;j<(Int_t)fSlices_mFadc;j++)
      {
        sig[i][j] += pedestal[i];
	sig_LG[i][j] += pedestal[i];
      }

  //
  // AM 15 01 2003: Formerly the above operation was performed only 
  // for pixels in which used[] was true. But to run camera with no noise
  // and get the right baseline on the pixels with no C-photons, we have 
  // to do it for all pixels.
  //
}


void MFadc::SetElecNoise(Float_t value1, Float_t value2, UInt_t n_in_pix){

  UInt_t i;
 
  fInnerPixelsNum = n_in_pix;

  cout<<"MFadc::SetElecNoise ... generating database for electronic noise."
      <<endl;

  for (i=0;i<(UInt_t (fSlices_mFadc))*1001;i++){
    noise[i]=GenElec->Gaus(0., value1 );
    noise_outer[i]=GenElec->Gaus(0., value2 );
  }

  cout<<"MFadc::SetElecNoise ... done"<<endl;

}

void MFadc::ElecNoise() {
  // ============================================================
  //
  //    adds the noise due to optronics and electronics 
  //    to the signal. This is noise which comes before the FADC,
  //    so it will be later scaled down in the low gain branch, if 
  //    the switch to low gain occurs.
  //
  UInt_t startslice;

  for ( Int_t i = 0 ; i < numpix; i++) {
    //
    //  but at the beginning we must check if this pixel is
    //  hitted the first time
    //

    startslice = GenElec->Integer(((Int_t)fSlices_mFadc)*1000);

    if ( used[i] == FALSE )
    {
	used [i] = TRUE ; 
	if (i < fInnerPixelsNum)
	  {
	    memcpy( (Float_t*)&sig[i][0],
		    (Float_t*)&noise[startslice], 
		    ((Int_t) fSlices_mFadc)*sizeof(Float_t));
	    memcpy( (Float_t*)&sig_LG[i][0],
		    (Float_t*)&noise[startslice], 
		    ((Int_t) fSlices_mFadc)*sizeof(Float_t));
	  }

	else
	  {
	    memcpy( (Float_t*)&sig[i][0],
		    (Float_t*)&noise_outer[startslice], 
		    ((Int_t) fSlices_mFadc)*sizeof(Float_t));
	    memcpy( (Float_t*)&sig_LG[i][0],
		    (Float_t*)&noise_outer[startslice], 
		    ((Int_t) fSlices_mFadc)*sizeof(Float_t));
	  }
    }

    //      
    //  If pixel already in use, the noise is added each time slice
    //
    else
    {
	if (i < fInnerPixelsNum)
	    for ( Int_t is = 0 ; is < (Int_t)fSlices_mFadc ; is++ ) 
	      {
		sig[i][is] += noise[startslice+is];
		sig_LG[i][is] += noise[startslice+is];
	      }
	else
	    for ( Int_t is = 0 ; is < (Int_t)fSlices_mFadc ; is++ ) 
	      {
		sig[i][is] += noise_outer[startslice+is];
		sig_LG[i][is] += noise_outer[startslice+is];
	      }
    }
  }
}

void MFadc::SetDigitalNoise(Float_t value){

  UInt_t i;
  Float_t xrdm;
 
  cout<<"MFadc::SetDigitalNoise ... generating database for electronic noise."
      <<endl;

  for (i=0;i<UInt_t(fSlices_mFadc*1001);i++){
    xrdm=GenElec->Gaus(0., value);
    digital_noise[i]=(xrdm>0?Int_t(xrdm+0.5):Int_t(xrdm-0.5));    
  }
  
  cout<<"MFadc::SetDigitalNoise ... done"<<endl;

}

void MFadc::DigitalNoise() {
  // ============================================================
  //
  //    adds the noise due to FADC electronics to the signal. This
  //    noise affects equally the high and low gain branches, that is, 
  //    it is not scaled down in the low gain branch.
  //
  UInt_t startslice;

  for ( Int_t i = 0 ; i < numpix; i++) 
    {
      if ( used[i] == FALSE )
	continue;

      startslice=GenElec->Integer((Int_t) fSlices_mFadc*999);
      //      
      //  Then the noise is introduced for each time slice
      //
      for ( Int_t is = 0 ; is < fFadcSlices; is++ ) 
	{ 
	  output[i][is] += digital_noise[startslice+is];
	  output_lowgain[i][is] += digital_noise[startslice+fFadcSlices+is];
	}
    }
}

void MFadc::Scan() {
  

  for ( Int_t ip=0; ip<numpix; ip++ ) {
    
    if ( used[ip] == kTRUE ) {

      printf ("Pid %3d",  ip ) ; 

      for ( Int_t is=0 ; is < (Int_t)fSlices_mFadc; is++ ) {

	if ( sig[ip][is] > 0. ) {
	  printf (" %4.1f/", sig[ip][is] ) ;
	}
	else {
	  printf ("----/" ) ;
	}
      }
      
      printf ("\n"); 

    }
  }
  
} 

void MFadc::Scan(Float_t time) {
  
  //
  //    first of all we subtract from the time a offset (8 ns) 
  // 
  
  Float_t t ; 

  (0 > time - TIME_BEFORE_TRIGGER)? t=fadc_time_offset: t=(time-TIME_BEFORE_TRIGGER+fadc_time_offset) ; // to show also the start of the pulse before the trigger time

  if ( t < 0. ) {
    cout << " WARNING!! FROM MFADC::SCAN(t) " << endl ; 
    exit (776) ;  
  }

  //
  //  calculate the first slice to write out
  // 
  
  Int_t  iFirstSlice ; 

  iFirstSlice = (Int_t) ( t * fFadcSlicesPerNanosec ) ; 

  for ( Int_t ip=0; ip<numpix; ip++ ) {
    
    if ( used[ip] == kTRUE ) {

      printf ("Pid %3d",  ip ) ; 

      for ( Int_t is=iFirstSlice ; is < (iFirstSlice+15); is++ ) {
	printf (" %5.2f /", sig[ip][is] ) ; 
      }
      
      printf ("\n"); 

    }
  }  
} 

void MFadc::GetResponse( Float_t *resp ) {
  // ============================================================
  //
  //    puts the standard response function into the array resp
  
  for ( Int_t i=0; i< fResponseSlicesFadc; i++ )
    resp[i] = sing_resp[i];

}

void MFadc::GetPedestals( Float_t *offset) {
  // ============================================================
  //
  //    puts the pedestal values into the array offset
  
  for ( Int_t i=0; i< numpix; i++ ) {

    offset[i] = pedestal[i] ; 
  }
}

//===========================================================================
//
// Next function adds up the noise in pixel "pix", scaling down the part
// of it which comes from before the receivers in the case we are dealing with
// low gain (ishigh=0). The output is the sum of the readouts of a number 
// n_slices of FADC slices. For the case of low gain, the FADC contents we add
// are not what we would have in a real pedestal event, but nevertheless this 
// is useful in the camera simulation to obtain what the pedestal fluctuations 
// are for the low gain. This will be written to the camera output, in the 
// MMcFadcHeader.
//
Float_t MFadc::AddNoiseInSlices( Int_t pix, Int_t ishigh, Int_t n_slices) {

  Float_t sum = 0;
  Float_t fvalue = 0.;
  UChar_t value = 0;
  UInt_t startslice;

  //
  // Get at random a point in the FADC presimulated digital noise:
  //
  startslice=GenElec->Integer((Int_t) fSlices_mFadc*999);

  for ( Int_t is=0; is < n_slices ; is++ ) 
    {
      if (ishigh)
	fvalue = sig[pix][is];
      else 
	// If we deal with low gain, we have to scale the values in sig_LG[][] by
	// the gain ratio (high2low_gain), since "sig_LG" contains at this point the 
	// noise produced before the receiver boards (for instance NSB noise).
	//
	fvalue = pedestal[pix]+(sig_LG[pix][is]-pedestal[pix]) / high2low_gain;

      fvalue += digital_noise[startslice+is]; // We add the noise intrinsic to FADC

      fvalue = fvalue < 0? fvalue-0.5 : fvalue+0.5;

      value = fvalue < 0.? (UChar_t) 0 :
	(fvalue > 255.? 255 : (UChar_t) fvalue);

      // Add up slices:
      sum += value - pedestal[pix];
    }

  return sum;
}

//=======================================================================

void MFadc::TriggeredFadc(Float_t time) {
  
  //
  // Here the slices to write out are calculated. Warning: the digitalization
  // is NOT done here (it is already done in MFadc::Fill). This procedure only
  // selects which FADC slices to write out, out of those contained in the sig[][]
  // and sig_LG[][] arrays.
  //

  //
  //  calculate the first slice to write out, according to trigger time: 
  // 
  
  Int_t iFirstSlice ; 
  Int_t i;

  //
  // We had 0.5 for the correct rounding:
  //
  iFirstSlice = (Int_t) ( 0.5 + time * fFadcSlicesPerNanosec ) ; 

  for ( Int_t ip = 0; ip < numpix; ip++ )
    {

      if ( used[ip] == kFALSE)
	// Pixels with no C-photons, in the case that camera is being run with
	// no noise (nor NSB neither electronic). We then set the mean pedestal as
	// signal, since when analyzing the camera output file, MARS will subtract 
	// it anyway!
	{
	  for ( Int_t i=0 ; i < fFadcSlices ; i++ ) 
	    {
	      output[ip][i] = pedestal[ip];
	      output_lowgain[ip][i] = pedestal[ip];
	    }
	  continue;
	}


      // First put the high gain in the output slices:
      i = 0;
      Int_t switch_i = 0;
      for ( Int_t is = iFirstSlice; is < (iFirstSlice+fFadcSlices); is++ ) 
	{
	  if (is < (Int_t)fSlices_mFadc)
	    {
	      output[ip][i] = sig[ip][is];
	      
	      if (switch_i == 0) // Hi gain limit not yet surpassed before.
		{
		  if (output[ip][i] > fGainSwitchAmp)
		    switch_i = i + fShiftFromSwitch2LowGain;
		}
	    }

	  else // We are beyond the simulated signal history in sig[][]! Put just mean pedestal!
	    output[ip][i] = pedestal[ip];

	  i++;
	}

      // Now put the low gain:
      i=0;
      for ( Int_t is = iFirstSlice; is < (iFirstSlice+fFadcSlices); is++ ) 
	{
	  if (is < (Int_t)fSlices_mFadc)
	    {
	      if (switch_i > 0 && (i+fFadcSlices) >= switch_i)
		output_lowgain[ip][i] = pedestal[ip] + 
		  (sig_LG[ip][is]-pedestal[ip])/high2low_gain;
	      // Once the shift occurs, low gain is filled with the high
	      // gain signal scaled down by the factor high2low_gain

	      else
		output_lowgain[ip][i] = sig[ip][is+fFadcSlices];
	      // Write out high gain into low gain slices if there was no 
	      // switch, or before the switch occurs.
	    }

	  else // We are beyond the simulated signal history in sig[][]! Put just mean pedestal!
	    {
	      output_lowgain[ip][i] = pedestal[ip];
	    }
	  i++;
	}

    }
}


void MFadc::ShowSignal (MMcEvt *McEvt, Float_t trigTime) { 
  // ============================================================
  //
  //  This method is used to book the histogram to show the signal in 
  //  a special gui frame (class MGTriggerSignal). After the look onto the
  //  signals for a better understanding of the things we will expect 
  //  the gui frame and all histogramms will be destroyed.   
  //
  
  //
  //  first of all create a list of the histograms to show
  //
  //  take only that one with a entry

  TH1F *hist ; 
  Char_t dumm[10]; 
  Char_t name[256]; 
  
  TObjArray  *AList ;
  AList = new TObjArray(10) ; 

  // the list of analog signal histograms
  // at the beginning we initalise 10 elements
  // but this array expand automatically if neccessay
  
  Int_t ic = 0 ; 
  for ( Int_t i=0 ; i < numpix; i++  ) {
    if ( used [i] == TRUE ) {

      sprintf (dumm, "FADC_%d", i ) ; 
      sprintf (name, "fadc signal %d", i ) ; 
      
      hist = new TH1F(dumm, name, (Int_t)fSlices_mFadc, fadc_time_offset, TOTAL_TRIGGER_TIME+fadc_time_offset); 
      //
      //  fill the histogram
      //
      
      for (Int_t ibin = 1; ibin <= (Int_t)fSlices_mFadc; ibin++)
	hist->SetBinContent (ibin, sig[i][ibin-1]);


      //      hist->SetMaximum( 5.);
      //      hist->SetMinimum(-10.);
      hist->SetStats(kFALSE); 
  
      //      hist->SetAxisRange(0., 80. ) ; 
      
      AList->Add(hist) ; 
      
      ic++ ; 
    }
  }  

  //
  //   create the Gui Tool
  //
  //
  
  new MGFadcSignal(McEvt,
  		   AList,
		   trigTime, 
  		   gClient->GetRoot(), 
		   gClient->GetRoot(), 
  		   400, 400 ) ; 
   
  //
  //   delete the List of histogramms
  //
  AList->Delete() ; 
  
  delete AList ; 
}

UChar_t MFadc::GetFadcSignal(Int_t pixel, Int_t slice){

  //  It returns the analog signal for a given pixel and a given FADC
  //  time slice which would be read.

  //  Since May 1 2004, we do the rounding and the truncation to the range 
  //  0-255 counts here. (A. Moralejo)

  Float_t out = output[pixel][slice] > 0. ? 
    output[pixel][slice]+0.5 : output[pixel][slice]-0.5; 
  // (add or subtract 0.5 for correct rounding)

  return (out < 0.? (UChar_t) 0 :
	  (out > 255.? (UChar_t) 255 : 
	   (UChar_t) out));
}

 
UChar_t MFadc::GetFadcLowGainSignal(Int_t pixel, Int_t slice){
 
   //  It returns the analog signal for a given pixel and a given FADC
   //  time slice which would be read. Same comment as above.
 
  Float_t outlow = output_lowgain[pixel][slice] > 0. ? 
    output_lowgain[pixel][slice]+0.5 : 
    output_lowgain[pixel][slice]-0.5; 
  // (add or subtract 0.5 for correct rounding)

  return (outlow < 0.? (UChar_t) 0 :
	  (outlow > 255.? (UChar_t) 255 : 
	   (UChar_t) outlow));
}



