#include "MLons.hxx"

using namespace std;

MLons::MLons()
{
  //-----------------------------------------------------------------
  //
  //   Default constructor
  //

  fTrigShape = 0;
  fAmplTrig = 1.0;  
  fFwhmTrig = 2.0;
  fFadcSlicesPerNanosec = FADC_SLICES_PER_NSEC;

  fFadcShape = 0;
  fIntegFadc = 1.0;
  fFwhmFadc = 2.0;

  fGainFluctuations = 1;

  RandomNumber = new TRandom();
  RandomNumber -> SetSeed(0);

}

MLons::MLons(Int_t in_shapeT, Float_t in_amplT, Float_t in_FwhmT, 
	     Int_t in_shapeF, Float_t in_integF, Float_t in_FwhmF,
	     Float_t in_Fadc_Slices_per_ns, Int_t in_Gain_Fluctuations)
{
  //--------------------------------------------------------------------
  //
  //  Constructor overloaded I
  //

  fTrigShape = in_shapeT;
  fAmplTrig = in_amplT; 
  fFwhmTrig = in_FwhmT;

  fFadcShape = in_shapeF;
  fIntegFadc = in_integF;
  fFwhmFadc = in_FwhmF;

  fFadcSlicesPerNanosec = in_Fadc_Slices_per_ns;

  fGainFluctuations = in_Gain_Fluctuations;

  MSLStored = new MStarLight;

  RandomNumber = new TRandom() ; 
  RandomNumber -> SetSeed(0);
}

void MLons::Reset() 
{
  //-----------------------------------------------------------------
  //
  //  Reset the member variables
  //

  fTrigShape   = 0; 
  fAmplTrig    = 0.; 
  fFwhmTrig    = 0.; 

  fFadcShape   = 0; 
  fIntegFadc   = 0.; 
  fFwhmFadc    = 0.; 

  fGainFluctuations = 1;

  MSLStored->Reset();

}

void MLons::SetSeed(UInt_t in)
{
  RandomNumber -> SetSeed(in);
}

Float_t MLons::GetAmplTrig () 
{
  return fAmplTrig  ; 
}

void MLons::SetAmplTrig (Float_t in ) 
{
  fAmplTrig = in ; 
}

Float_t  MLons::GetFwhmTrig () 
{
  return fFwhmTrig  ; 
}

void MLons::SetFwhmTrig (Float_t in ) 
{
  fFwhmTrig = in ; 
}


Float_t MLons::GetIntegFadc () 
{
  return fIntegFadc  ; 
}

void MLons::SetIntegFadc (Float_t in ) 
{
  fIntegFadc = in ; 
}

Float_t  MLons::GetFwhmFadc () 
{
  return fFwhmFadc  ; 
}

void MLons::SetFwhmFadc (Float_t in ) 
{
  fFwhmFadc = in ; 
}

void MLons::SetPath (Char_t in[])
{
  strcpy(path, & in[0]);  
}

void MLons::ReadBinaryMStarLight(char *filename)
{
  MSLStored->ReadBinary(filename); 
}

Int_t MLons::CheckTrig()
{
  //--------------------------------------------------------------------
  //
  //  Parameters of MSLStored should be the same than the required ones
  //

  if (  fAmplTrig == MSLStored->GetAmplTrig() && 
	fFwhmTrig == MSLStored->GetFwhmTrig())
    return 1;

  cout << "1 phe- pulse amplitudes for trigger (mV): " << fAmplTrig << "    "
       << MSLStored->GetAmplTrig() << endl;
  cout << "1 phe- pulse FWHM for trigger (ns):       " << fFwhmTrig << "    "
       << MSLStored->GetFwhmTrig() << endl;

  return 0;
}

Int_t MLons::CheckFADC()
{
  //--------------------------------------------------------------------
  //
  //  Parameters of MSLStored should be the same than the required ones
  //

  if (  fIntegFadc == MSLStored->GetIntegFadc() && 
	fFwhmFadc == MSLStored->GetFwhmFadc() && 
	fFadcShape == MSLStored->GetShapeFadc() &&
	fFadcSlicesPerNanosec == MSLStored->GetFadcSlicesPerNanosec() )
    return 1;

  cout << "1 phe- FADC pulse shape :             " << fFadcShape << "    " 
       << MSLStored->GetShapeFadc() <<  endl;
  cout << "1 phe- FADC pulse integral (counts) : " << fIntegFadc << "    " 
       << MSLStored->GetIntegFadc() << endl;
  cout << "1 phe- FADC pulse FWHM (ns) :         " << fFwhmFadc  << "    " 
       << MSLStored->GetFwhmFadc() <<  endl;
  cout << "FADC sampling frequencies (GHz) :     " << fFadcSlicesPerNanosec << "    "
       << MSLStored->GetFadcSlicesPerNanosec() << endl;

  return 0;
}

Int_t MLons::GetResponse(Float_t in_br, Float_t in_pre,
			 Float_t *out_tr, Float_t *out_Fr)
{
  //-------------------------------------------------------------------------
  //
  //   It reads the response from the database and put it in out_tr
  //

  Char_t filename_slt[256];
  Char_t cbright[10];
  Char_t cstoredbright[10];

  Int_t bin;
  Float_t start_time;


  //
  // The following code line commented means that the simulation will crash if
  // some pixel ask for more lons than what we have in the database.
  // The following code line uncommented would mean that the simulation does
  // not crash if a pixel ask for more than it is simulated but would 
  // assign to it less lons.
  // I think this is unnecessary now. AM 5/10/2004
  //  if (in_br>49.9) in_br=49.9;    //  To avoid error for high required brightness
  //                                 //  It has to be improved
  //


  //  Check if the the brightness is the same than the last time.
  //  NOTE: Same means, the same inside the required precision!!!

  if(in_br<=1.0){
    sprintf(cbright,"%4.2f",in_br);
    sprintf(cstoredbright,"%4.2f",MSLStored->GetBrightness());
  }
  else{
    sprintf(cbright,"%3.1f",in_br);
    sprintf(cstoredbright,"%3.1f",MSLStored->GetBrightness());
  }

  if (strcmp(cbright, cstoredbright))
    {
      // Building the filename
      // Note: it would be nice to get an algorithm that gets the name of 
      // files it needs to get brightness as a function of precison(in_pre),
      // brightnes (in_br) and the Star_files that are in the "Path" directory.

      strcpy(filename_slt, & path[0]);
      strcat(filename_slt, "Brightness");
      strcat(filename_slt, & cbright[0]);
  
      strcat(filename_slt, ".slt");
 
      // If brightness is different it checks if the new file has the
      // required parameters.
      // Note: I could be faster to store the whole trigger and fadc
      // response and use it while brightness does not change. Then the
      // root file should be open and close here.

      MSLStored->ReadBinary(filename_slt); 

      if (!(CheckTrig() && CheckFADC()))
	{
	  cout << "ERROR: The Database for light from Night Sky Background is wrong"<<endl;
	  cout << "       Make sure that you generated the database with the same shape" << endl;
	  cout << "       for Fadc and trigger that you are asking now."<<endl; 
	  return 0;
	}

      if ( !MSLStored->GetGainFluctuations() && fGainFluctuations)
	{
	  cout << endl << "ERROR! The read NSB database in " << filename_slt << endl;
	  cout << "has been produced without PMT gain fluctuations. This is incompatible" << endl;
	  cout << "with the camera input card you are using. Please change the camera" << endl;
	  cout << "input card (adding the  noise_gain_fluctuations_off  command) or"  << endl;
	  cout << "produce a new NSB database (using program StarResponse) without" << endl;
	  cout << "gain fluctuations. Exiting..." << endl << endl;
	  return 0;
	}

      else if ( MSLStored->GetGainFluctuations() && !fGainFluctuations)
	{
	  cout << endl << "ERROR! The read NSB database in " << filename_slt << endl;
	  cout << "has been produced with PMT gain fluctuations. This is incompatible" << endl;
	  cout << "with the camera input card command  noise_gain_fluctuations_off" << endl;
	  cout << "that you are using. Please change the camera input card or produce a" << endl;
	  cout << "new NSB database (using program StarResponse) without gain fluctuations." << endl;
	  cout << "Exiting..." << endl << endl;
	  return 0;
	}

      MSLStored->SetBrightness(in_br);

    }

  // Random number that decides the set of bins that the program will get
  start_time = RandomNumber->Uniform(TIMERANGE);

  //  Filling trigger response

  bin = (Int_t)(start_time*TRIG_SLICES_PER_NSEC);


  if (bin+TRIGGER_TIME_SLICES > MSLStored->GetBinsTrig())
    {
      memcpy (out_tr, MSLStored->GetTrigPointer(bin), 
	      (UInt_t) (MSLStored->GetBinsTrig()-bin)*sizeof(Float_t));
      memcpy (out_tr, MSLStored->GetTrigPointer(0),
	      (UInt_t) (bin+TRIGGER_TIME_SLICES-MSLStored->GetBinsTrig())*sizeof(Float_t));
    }
  else
    memcpy (out_tr, MSLStored->GetTrigPointer(bin), 
	    (UInt_t) TRIGGER_TIME_SLICES*sizeof(Float_t));


  //  Filling fadc response

  // Start bin in the NSB database:
  bin = (Int_t) (start_time*MSLStored->GetBinsFadc()/MSLStored->GetTimeRange()); 

  // If we go over the end of the database, continue at the begining of it: 
  if (bin + (Int_t)(TOTAL_TRIGGER_TIME*fFadcSlicesPerNanosec) > MSLStored->GetBinsFadc())
    {
      memcpy (out_Fr, MSLStored->GetFadcPointer(bin), 
	      (Int_t)(MSLStored->GetBinsFadc()-bin)*sizeof(Float_t));

      memcpy (out_Fr + MSLStored->GetBinsFadc() - bin, 
	      MSLStored->GetFadcPointer(0),
	      (Int_t)(bin + TOTAL_TRIGGER_TIME*fFadcSlicesPerNanosec - 
		      MSLStored->GetBinsFadc())*sizeof(Float_t));
    }
  else
    memcpy (out_Fr, MSLStored->GetFadcPointer(bin), 
	    (Int_t)(TOTAL_TRIGGER_TIME*fFadcSlicesPerNanosec*sizeof(Float_t)));

  return 1;
}
