/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!   Author(s): Javier Lopez    04/2004 <mailto:jlopez@ifae.es>
!   Author(s): Javier Rico     04/2004 <mailto:jrico@ifae.es>
!
!   Copyright: MAGIC Software Development, 2000-2004
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//
// MSrcPlace
//
// Abstract task to set the source position in any place in the camera
// It keeps a 2D histogram with the assigned positions, so that the same
// distribution can be applied later to any data set (tipically the OFF data)
// Classes inheritating MSrcPlace should override the ComputeNewSrcPosition() 
// method and probably include a call to MsrcPlace::PreProcess in their
// PreProcess method (see, e.g., MSrcPosFromFile or MSrcRotate classes)
//
//  Input Containers:
//    MSrcPosCam
//
//  Output Containers:
//    MSrcPosCam
//    MDCA
//
//////////////////////////////////////////////////////////////////////////////

#include <fstream>
#include <math.h>

#include "TH2F.h"

#include "MParList.h"
#include "MSrcPlace.h"
#include "MSrcPosCam.h"
#include "MDCA.h"

#include "MLog.h"
#include "MLogManip.h"

ClassImp(MSrcPlace);

using namespace std;

static const TString gsDefName  = "MSrcPlace";
static const TString gsDefTitle = "Set the position of the source";

// -------------------------------------------------------------------------
//
// Default constructor. The first argument is the name of the internal histo, 
// the second (third) argument is the name of a container
// containing the source position in the camera plain, MScrPosCam (MDCA).
// The default is "MSrcPosCam" ("MDCA"). 
//
MSrcPlace::MSrcPlace(const char* histname, const char* srcPos, const char* dca, const char *name, const char *title)
  : fSrcPos(NULL), fDCA(NULL)
{
    fName  = name  ? name  : gsDefName.Data();
    fTitle = title ? title : gsDefTitle.Data();

    fSrcPosName  = srcPos;
    fDCAName     = dca;

    const Float_t cameraSize   = 600; //[mm]
    const Float_t binPrecision =   1; //[mm] ~ 0.0033 deg  
    const UInt_t nbins =  (UInt_t)(cameraSize*2/binPrecision);
    
    fHistPos = new TH2F(histname,"",nbins,-cameraSize,cameraSize,nbins,-cameraSize,cameraSize);

    fMode=kOn;
}
// -------------------------------------------------------------------------
//
// Destructor
//
MSrcPlace::~MSrcPlace()
{
  if(fHistPos)
    delete fHistPos;
}

// -------------------------------------------------------------------------
//
// Save the position of the source in the histogram
//
void MSrcPlace::SavePosIntoHisto()
{  
  fHistPos->Fill(fSrcPos->GetX(),fSrcPos->GetY());
}
// -------------------------------------------------------------------------
//
// Read the position of the source from the histogram
//
void MSrcPlace::ReadPosFromHisto()
{  
  Axis_t x;
  Axis_t y;
  
  fHistPos->GetRandom2(x,y);
  fSrcPos->SetXY(x,y);
  fDCA->SetRefPoint(x,y);
}
// -------------------------------------------------------------------------
//
// Look for needed containers.
// Check processing mode and if histogram is filled in case kOff mode
//
Int_t MSrcPlace::PreProcess(MParList* pList)
{ 
    // look for/create MSrcPosCam
  fSrcPos = (MSrcPosCam*)pList->FindObject(AddSerialNumber(fSrcPosName), "MSrcPosCam");
  if (!fSrcPos)
    {
      *fLog << warn << AddSerialNumber(fSrcPosName) << " [MSrcPosCam] not found... creating default container." << endl;
      fSrcPos = (MSrcPosCam*)pList->FindCreateObj("MSrcPosCam", AddSerialNumber(fSrcPosName));
      if(!fSrcPos)
	return kFALSE;
    }

  // look for/create MDCA
  fDCA = (MDCA*)pList->FindObject(AddSerialNumber(fDCAName), "MDCA");
  if (!fDCA)
    {
      *fLog << warn << AddSerialNumber(fDCAName) << " [MDCA] not found... creating default container." << endl;
      fDCA = (MDCA*)pList->FindCreateObj("MDCA", AddSerialNumber(fDCAName));
      if(!fDCA)
	return kFALSE;
    }

  // check mode, look for a filled histogram in case kOff
  if(fMode==kOn)
    *fLog << inf << "MSrcPlace PreProcess Message: source postions will be stored in internal histo (" << fHistPos->GetName() << ")" << endl;
  else
    {
      if(fHistPos->GetEntries())
	*fLog << inf << "MSrcPlace PreProcess Message: source postions will be read from internal histo (" << fHistPos->GetName() << ")" << endl;
      else
	{
	  *fLog << err << "MSrcPlace PreProcess Error: source postions attempted to be read from empty histo (" << fHistPos->GetName() << ")" << endl;
	  return kFALSE;
	}
    }
  return kTRUE;
}

// -------------------------------------------------------------------------
//
// Call to compute a new position and then save it in the histogram (fMode==kOn) 
// of to read the new position from the histogram (fMode==kOff)
//
Int_t MSrcPlace::Process()
{  
  switch(fMode)
    {
    case kOn:
      if(!ComputeNewSrcPosition())
	return kFALSE;
      SavePosIntoHisto();
      break;
    case kOff:
      ReadPosFromHisto();
      break;
    default:
      *fLog << err << "MSrcPlace::Process Warning: Wrong mode " << fMode << endl;
      return kFALSE;
    }
  return kTRUE;
}

// -------------------------------------------------------------------------
//
// Dump 2D histo statistics
//
Int_t MSrcPlace::PostProcess()
{
  if(fMode==kOn)
    {
      *fLog << inf << endl;
      *fLog << inf << "MSrcPlace::PostProcess Message: Created internal histogram with: " << endl;
      *fLog << inf << "Entries: " << fHistPos->GetEntries() << endl;
      *fLog << inf << "X projection mean: " << fHistPos->ProjectionX()->GetMean() << endl;
      *fLog << inf << "X projection rms:  " << fHistPos->ProjectionX()->GetRMS() << endl;
      *fLog << inf << "Y projection mean: " << fHistPos->ProjectionY()->GetMean() << endl;
      *fLog << inf << "Y projection rms:  " << fHistPos->ProjectionY()->GetRMS() << endl;
    }
  return kTRUE;
}
