/* ======================================================================== *\
!
! *
! * 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 the input (output) container
// containing the source position in the camera plain. Fourth argument is the
// name of the output MDCA container.
//
MSrcPlace::MSrcPlace(const char* srcPosIn, const char* srcPosOut, const char* dca, const char *name, const char *title)
  : fSrcPosIn(NULL), fSrcPosOut(NULL), fDCA(NULL), fHistoName("SrcPosHist"), 
    fHistoBinPrec(1.), fHistPos(NULL)
{
    fName  = name  ? name  : gsDefName.Data();
    fTitle = title ? title : gsDefTitle.Data();

    fSrcPosInName   = srcPosIn;
    fSrcPosOutName  = srcPosOut;
    fDCAName        = dca;

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

// -------------------------------------------------------------------------
//
// Save the position of the source in the histogram
//
void MSrcPlace::SavePosIntoHisto()
{  
  if(fHistPos)
    fHistPos->Fill(fSrcPosOut->GetX(),fSrcPosOut->GetY());
}
// -------------------------------------------------------------------------
//
// Read the position of the source from the histogram
//
void MSrcPlace::ReadPosFromHisto()
{  
  if(fHistPos)
    {
      Axis_t x;
      Axis_t y;
      
      fHistPos->GetRandom2(x,y);
      fSrcPosOut->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)
{ 
  // create (if needed and requested) internal histogram
  if(fCreateHisto && !fHistPos)
    {
      const Float_t cameraSize   = 600; //[mm]
      const UInt_t nbins =  (UInt_t)(cameraSize*2/fHistoBinPrec);
      fHistPos = new TH2F(fHistoName,"",nbins,-cameraSize,cameraSize,nbins,-cameraSize,cameraSize);
      fHistPos->SetDirectory(0);
      *fLog << inf << "MSrcPlace::PreProcess Message: internal histogram " << fHistoName << " created with " << nbins << "x" << nbins << " bins" << endl;
    }

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

  // look for/create output MSrcPosCam
  fSrcPosOut = (MSrcPosCam*)pList->FindObject(AddSerialNumber(fSrcPosOutName), "MSrcPosCam");
  if (!fSrcPosOut)
    {
      *fLog << warn << AddSerialNumber(fSrcPosOutName) << " [MSrcPosCam] not found... creating default container." << endl;
      fSrcPosOut = (MSrcPosCam*)pList->FindCreateObj("MSrcPosCam", AddSerialNumber(fSrcPosOutName));
      if(!fSrcPosOut)
	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(fHistPos)
    {
      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 && fHistPos)
    {
      *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;
}
