/* ======================================================================== *\
!
! *
! * 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): Thomas Bretz, 01/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
!
!   Copyright: MAGIC Software Development, 2000-2003
!
!
\* ======================================================================== */

/////////////////////////////////////////////////////////////////////////////
//
// MFEventSelector
//
// This is a filter to make a selection of events from a file. At the
// present implementation you can only use a random selection.
//
// If you want to fill only 50% of your events into a histogram please use:
//   MFEventSelector sel;
//   sel.SetSelectionRatio(0.5);
//   MFillH filler(...);
//   filler.SetFilter(&sel);
//   tlist.AddToList(&sel);
//   tlist.AddToList(&filler);
//
// To get around 2000 events from all events use (Remark: This will only
// work if the parlist has an entry called MTaskList which has a task
// MRead inheriting from MRead):
//   MFEventSelector sel;
//   sel.SetNumSelectEvts(2000);
//   MFillH filler(...);
//   filler.SetFilter(&sel);
//   tlist.AddToList(&sel);
//   tlist.AddToList(&filler);
//
// If you don't have MRead available you have to set the number of
// total events manually, using sel.SetNumTotalEvts(10732);
//
// The random number is generated using gRandom->Uniform(). You may
// control this procedure using the global object gRandom.
//
// Because of the random numbers this works best for huge samples...
//
// Don't try to use this filter for the reading task: This won't work!
//
// Remark: You can also use the filter together with MContinue
//
/////////////////////////////////////////////////////////////////////////////
#include "MFEventSelector.h"

#include <TRandom.h>

#include "MParList.h"
#include "MTaskList.h"
#include "MRead.h"

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

ClassImp(MFEventSelector);

using namespace std;

static const TString gsDefName  = "MFEventSelector";
static const TString gsDefTitle = "Filter to select events";

// --------------------------------------------------------------------------
//
// Default Constructor. Don't use.
//
/*
MFEventSelector::MFEventSelector()
    : fNumTotalEvts(-1), fNumSelectEvts(-1), fSelRatio(-1), fNumSelectedEvts(0)
{
    fName  = gsDefName.Data();
    fTitle = gsDefTitle.Data();
}
*/
// --------------------------------------------------------------------------
//
// Constructor. For the text describing the filter rule please see
// the class description above.
//
MFEventSelector::MFEventSelector(const char *name, const char *title)
: fNumTotalEvts(-1), fNumSelectEvts(-1), fSelRatio(-1), fNumSelectedEvts(0)
{
    fName  = name  ? name  : gsDefName.Data();
    fTitle = title ? title : gsDefTitle.Data();
}

// --------------------------------------------------------------------------
//
// PreProcess all filters.
//
Int_t MFEventSelector::PreProcess(MParList *plist)
{
    memset(fErrors, 0, sizeof(fErrors));

    fNumSelectedEvts = 0;
    if (fSelRatio>0)
        return kTRUE;

    if (fNumTotalEvts<0)
    {
        MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
        if (!tlist)
        {
            *fLog << err << dbginf << "Sorry can't determin total number of events... no MTaskList." << endl;
            return kFALSE;
        }

        MRead *read = (MRead*)tlist->FindObject("MRead");
        if (!read)
        {
            *fLog << err << dbginf << "Sorry can't determin total number of events from 'MRead'." << endl;
            return kFALSE;
        }
        fNumTotalEvts = read->GetEntries();

        *fLog << "MFEventSelector::PreProcess; fNumTotalEvts = " 
              << fNumTotalEvts << endl;

        SetBit(kNumTotalFromFile);
    }

    return kTRUE;
}

// --------------------------------------------------------------------------
//
// Process all filters.
//
Int_t MFEventSelector::Process()
{
    Int_t rc;

    const Float_t evt = gRandom->Uniform();

    if (fNumSelectEvts>0)
        fResult = evt*fNumTotalEvts < fNumSelectEvts;
    else
        fResult = evt < fSelRatio;

    if (fResult)
    {
        fNumSelectedEvts++;

        rc = 0;
        fErrors[rc]++;
        return kTRUE;
    }
    
    rc = 1;
    fErrors[rc]++;

    return kTRUE;
}

// --------------------------------------------------------------------------
//
//  Postprocess all filters.
//
Int_t MFEventSelector::PostProcess()
{
    //---------------------------------
    if (GetNumExecutions() != 0)
    {
      *fLog << inf << endl;
      *fLog << GetDescriptor() << " execution statistics:" << endl;
      *fLog << dec << setfill(' ');
      *fLog << " " << setw(7) << fErrors[1] << " (" << setw(3) 
            << (int)(fErrors[1]*100/GetNumExecutions()) 
            << "%) Events not selected" << endl;

      *fLog << " " << fErrors[0] << " (" 
            << (int)(fErrors[0]*100/GetNumExecutions()) 
            << "%) Events selected!" << endl;
      *fLog << endl;
    }

    //---------------------------------
    if (TestBit(kNumTotalFromFile))
        fNumTotalEvts = -1;
    return kTRUE;
}

void MFEventSelector::StreamPrimitive(ofstream &out) const
{
    /*
    out << "   MF " << GetUniqueName();

    if (!fFilter)
    {
        out << ";" << endl;
        return;
    }

    out << "(\"" << fFilter->GetRule() << "\"";
        if (fName!=gsDefName || fTitle!=gsDefTitle)
    {
        out << "(\"" << fName << "\"";
        if (fTitle!=gsDefTitle)
            out << ", \"" << fTitle << "\"";
    }
    out << ");" << endl;
    */

}
