/////////////////////////////////////////////////////////////////
//
//  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"

MFadc::MFadc() { 
  //
  //  default constructor 
  //  
  //  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
  
  fwhm_resp = MFADC_RESPONSE_FWHM       ; 
  ampl_resp = MFADC_RESPONSE_AMPLITUDE  ; 
  
  //
  //    set up the response shape
  // 
  Int_t  i,j ; 
  
  Float_t   sigma ; 
  Float_t   x, x0 ; 

  sigma = fwhm_resp / 2.35 ; 
  x0 = 3*sigma ; 
  
  Float_t   dX, dX2 ; 
  
  dX  = WIDTH_FADC_TIMESLICE / SUBBINS ; 
  dX2 = dX/2. ; 
  
  for (i=0; i< RESPONSE_SLICES_MFADC ; i++ ) {  

    x = i * dX + dX2 ; 
    
    //
    //   the value 0.125 was introduced to normalize the things
    //
    sing_resp[i] = 0.125 *  
      ampl_resp * expf(-0.5 * (x-x0)*(x-x0) / (sigma*sigma) ) ; 

  } 

  //
  //    init the Random Generator for Electonic Noise
  //

  GenElec = new TRandom () ; 

  //
  //  set all the booleans used to FALSE, indicating that the pixel is not 
  //  used in this event. 
  //
  
  for ( i =0 ; i <CAMERA_PIXELS ; i++ ) { 
    used [i] = FALSE ; 
  }

  //
  //  set tha values of FADC slices that would be read after trigger to zero
  //
  
  for (i=0; i <CAMERA_PIXELS; i++){
    for (j=0; j<FADC_SLICES;j++){
       output[i][j]=0;
    }
  }

}

  
void MFadc::Reset() { 
  //
  //  set all values of the signals to zero
  //
  Int_t  i,j ; 
  
  for ( i =0 ; i <CAMERA_PIXELS ; i++ ) {
    used [i] = FALSE ; 
  } 
  //
  //  set tha values of FADC slices that would be read after trigger to zero
  //
  
  for (i=0; i <CAMERA_PIXELS; i++){
    for (j=0; j<FADC_SLICES;j++){
       output[i][j]=0;
    }
  }
}


void MFadc::Fill( Int_t iPix, Float_t time, Float_t amplitude ) { 
  
  //
  // fills the information about one single Phe in the Trigger class
  //
  // parameter is the number of the pixel and the time-difference to the
  // first particle
  //
  //

  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 pixels
  // 
  if ( iPix > CAMERA_PIXELS ) {
    cout << " WARNING:  MFadc::Fill() :  iPix greater than CAMERA_PIXELS"
	 << endl ;
    exit(987) ; 
  }

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

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

  
  if ( time < 0. ) {
    cout << "  WARNING! Fadc::Fill  " << time << "  below ZERO!! Very strange!!" 
	 << endl ; 
  }
  else if ( time < TOTAL_TRIGGER_TIME ) { 
    //
    //   determine the slices number assuming the WIDTH_RESPONSE_MFADC
    //
    ichan = (Int_t) ( time / ((Float_t) WIDTH_RESPONSE_MFADC )); 

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

    for ( i = 0 ; i<RESPONSE_SLICES; i++ ) {
      ichanfadc = (Int_t) ((ichan+i)/SUBBINS) ; 
      if ( (ichanfadc) < SLICES_MFADC ) {  
	sig[iPix][ichanfadc] += (amplitude * sing_resp[i] )  ; 
      } 
    }
  }
  else {
    cout << "  WARNING!  Fadc::Fill " << time << "  out of TriggerTimeRange " 
	 << TOTAL_TRIGGER_TIME << endl ; 
  }

}

void MFadc::Baseline(){
  //  
  //  It simulates the AC behaviour

  int i,j;
  Float_t baseline;

  for(j=0;j<CAMERA_PIXELS;j++){
    baseline=0.0;
    for(i=0;i<(Int_t) SLICES_MFADC;i++){
      baseline=+sig[j][i];
    }
    baseline=baseline/SLICES_MFADC;
    for(i=0;i<(Int_t) SLICES_MFADC;i++){
      sig[j][i]=-baseline;
    }
  }
}

void MFadc::Offset(Float_t offset, Int_t pixel){
  // 
  //  It puts an offset in the FADC signal
  //

  int i,j;
  float fdum;
  TRandom *GenOff = new TRandom () ; 

  if (offset<0) {
    //  It cannot be, so the program assumes that 
    //  it should generate random values for the offset.

    if (pixel<0) {
      // It does not exist, so all pixels will have the same offset

      for(i=0;i<CAMERA_PIXELS;i++){
	if (used[i]){
	  fdum=(10*GenOff->Rndm());
	  for(j=0;j<(Int_t) SLICES_MFADC;j++)
	    sig[i][j]=+fdum;
	}
      }
    } else {
      // The program will put the specifies offset to the pixel "pixel".

      if (used[pixel]){
	fdum=(10*GenOff->Rndm());
	for(j=0;j<(Int_t) SLICES_MFADC;j++)
	  sig[pixel][j]=+fdum;
	}

    }
  }else {
    //  The "offset" will be the offset for the FADC

    if (pixel<0) {
      // It does not exist, so all pixels will have the same offset

      for(i=0;i<CAMERA_PIXELS;i++){
	if (used[i]){
	  for(j=0;j<(Int_t) SLICES_MFADC;j++)
	    sig[i][j]=+offset;
	}
      }
    } else {
      // The program will put the specifies offset to the pixel "pixel".

      if (used[pixel]){
	for(j=0;j<(Int_t) SLICES_MFADC;j++)
	  sig[pixel][j]=+offset;
      }
    }
  }
}

void MFadc::ElecNoise() {
  //
  //  
  //
  
  for ( Int_t i = 0 ; i < CAMERA_PIXELS; i++) {
    if ( used [i] == TRUE ) {
      for ( Int_t is=0 ; is< SLICES_MFADC ; is++ ) {

	sig[i][is] += GenElec->Gaus(0., 2.) ; 

      }
    }
  }
}



void MFadc::Scan() {
  

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

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

      for ( Int_t is=0 ; is < SLICES_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=0: t=(time-TIME_BEFORE_TRIGGER) ; // 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 /  WIDTH_FADC_TIMESLICE ) ; 

  for ( Int_t ip=0; ip<CAMERA_PIXELS; 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< RESPONSE_SLICES; i++ ) {

    resp[i] = sing_resp[i] ; 
  }
}
 
void MFadc::TriggeredFadc(Float_t time) {
  
  //
  //    first of all we subtract from the time a offset (8 ns) 
  // 
  
  Float_t t ; 

  (0>time-TIME_BEFORE_TRIGGER)? t=0: t=(time-TIME_BEFORE_TRIGGER) ; // 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 ; 
  Int_t i;

  iFirstSlice = (Int_t) ( t /  WIDTH_FADC_TIMESLICE ) ; 

  for ( Int_t ip=0; ip<CAMERA_PIXELS; ip++ ) {
    
    if ( used[ip] == kTRUE ) { 
      i=0;
      for ( Int_t is=iFirstSlice ; is < (iFirstSlice+FADC_SLICES) ; is++ ) {
	if (is< SLICES_MFADC)
	  output[ip][i++]=(UChar_t) sig[ip][is];
	else 
	  output[ip][i++]= 0;
      }

    }
  }  
} 

void MFadc::ShowSignal (MMcEvt *McEvt, Float_t trigTime) { 
  // ============================================================
  //
  //  This method is used to book the histogramm 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 automaticly if neccessay
  
  Int_t ic = 0 ; 
  for ( Int_t i=0 ; i < CAMERA_PIXELS; i++  ) {
    if ( used [i] == TRUE ) {

      sprintf (dumm, "FADC_%d", i ) ; 
      sprintf (name, "fadc signal %d", i ) ; 
      
      hist = new TH1F(dumm, name, SLICES_MFADC, 0., TOTAL_TRIGGER_TIME); 
      //
      //  fill the histogram
      //
      
      for (Int_t ibin=1; ibin <=SLICES_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 ; 
}

Float_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.

  return (output[pixel][slice]);
}


