/*
 * PamCutBase.h
 *
 *  Created on: 6-feb-2009
 *      Author: Nicola Mori
 */

/*! \file PamCutBase.h PamCut and PamCutCollection classes definitions. */

#ifndef PAMCUTBASE_H_
#define PAMCUTBASE_H_

#include <PamLevel2.h>
#include "../CommonDefs.h"

using namespace std;

/*! @brief An abstract class to apply cuts to Pamela data.
 *
 * This class provides a basic interface for a cut object to apply to PamLevel2 data.
 */
class PamCut {
public:

  /*! @brief Constructor.
   *  @param cutName The cut's name.
   */
  PamCut(const char *cutName) :
    _cutName(cutName), _nEv(0), _nGood(0) {
  }

  /*! @brief Destructor. */
  virtual ~PamCut() {
  }

  /*! @brief The basic event check.
   *
   *  This routine applies the cut to the currently selected event, eg., to the event selected
   *  by the last PamLevel2::GetEntry() call performed by the object pointed by event. Note that
   *  OnGood() is not called by this method.
   *
   * @param event The event to analyze.
   * @return #CUTOK if the event satisfy the cut, other return values are implementation-specific.
   */

  virtual int Check(PamLevel2 *event) = 0;

  /*! @brief Applies the cut to the current event.
   *
   *  This routine applies the cut to the currently selected event, eg., it calls Check() and if the
   *  event satisfy the selection it consequently call OnGood(), otherwise it calls OnBad()(this is
   *  the only difference with Check()).
   *
   * @param event The event to analyze.
   * @return same return values as Check()
   */
  virtual int ApplyCut(PamLevel2 *event);

  /*! @brief Applies the cut to a range of events.
   *
   * This method resets the counters calling Reset() and then calls ApplyCut(PamLevel2 *event) for all
   * the events in PamLevel2 argument inside the specified range. After checking all the events, it calls
   * the private method _Finalize(), on which the tasks to be performed after the selection can be defined.
   *
   * @param events Pointer to PamLevel2 object which contains the events.
   * @param firstEvent The first event to analyze. Possible values range from 0 to \#events - 1.
   * @param lastEvent The last event to analyze.
   */
  virtual void Process(PamLevel2 *events, ULong_t firstEvent, ULong_t lastEvent);

  /*! @brief Post-selection tasks.
   *
   * Here the post-selection actions (histogram filling, parameter calculation etc.) can be  defined.
   * This routine is automatically called after a good event has been selected by
   * ApplyCut().
   * @param event The event which satisfy the cut.
   */
  virtual void OnGood(PamLevel2 *event) {
  }

  /*! @brief Post-selection tasks.
   *
   * The post-selection tasks for bad events (ie., not satisfying the cut) can be defined here.
   *
   * @see OnGood
   * @param event The event which don't satisfy the cut.
   * @param selectionResult The return value of the Check() routine.
   */
  virtual void OnBad(PamLevel2 *event, int selectionResult) {
  }

  /*! @brief Returns the number of checked events.
   *
   * @return The number of checked events.
   */
  virtual UInt_t GetNEv() {
    return _nEv;
  }
  /*! @brief Returns the number of good events.
   *
   * This counter keeps track of how many events have fulfilled the
   * conditions specified in Check.
   *
   * @return The number of good events.
   */
  virtual UInt_t GetNGood() {
    return _nGood;
  }

  /*! @brief Returns the index of currently processed event.
    *
    * This method returns the index of the currently processed event inside a #Process()
    * invocation. It has no meaning when read outside #Process().
    *
    * @return The index of the currently processed event.
    */
  ULong_t GetCurrentEvent(){
    return _currEv;
  }

  /*! @brief The pre-analysis task definition.
   *
   * This method is automatically called by Process() before the event selection;
   * override this in derived classes to perform pre-analysis tasks like opening files and so on.
   * In this base class implementation it only resets the counters for examined and good events.
   * The parameter PamLevel2 *events may serve to initialize the analysis (even if in this base class
   * implementation it is unused), so the interface includes it.
   *
   * @param events The PamLevel2 pointer to the events that will be analyzed.
   *
   * @see GetNEv(), GetNGood().
   */
  virtual void Setup(PamLevel2 *events);

  /*! @brief The post-analysis task definition.
   *
   * This method is automatically called by Process() after the event selection has been
   * performed; override this in derived classes to perform post-analysis tasks like writing
   * histograms, closing files and so on.
   */
  virtual void Finalize() {
  }

  /*! @brief Returns the cut name.
   *
   * @return The cut name.
   */
  const char* GetName() const;

  /*! @brief Changes the cut's name
   *
   * @param newName The new name.
   */
  void SetName(const char *newName);

  /*! @brief The assignment operator.
   * This operator defines how to copy a PamCut object into another. In current implementation,
   * it only copies the cut's name of the RHS on the LHS.
   *
   * @param rightValue The RHS.
   * @return The new value for LHS.
   */
  PamCut& operator=(const PamCut &rightValue);

private:

  const char *_cutName;
  ULong_t _currEv;

protected:

  UInt_t _nEv; ///<  The number of analyzed events.
  UInt_t _nGood; ///<  The number of good events.
};

/*! @brief A class which applies a set of cuts to Pamela data.
 *
 * This is a multi-cut class, which inherits from PamCut. Indeed, a multi-cut can be seen as a cut composed
 * by various simpler cuts; hence the interface of PamCut is also functional for PamCutCollection. The
 * ApplyCut(PamLevel2 *event) method is overridden so as all the cuts that compose the PamCutCollection are applied to the
 * events in the same order they are added to the collection. Instead, Process(PamLevel2 *events, ULong_t firstEvent, ULong_t lastEvent)
 * is NOT overridden, since it performs the same task as the one in the base class: it is sufficient to override
 * Check(PamLevel2 *event) to replace the single-cut evaluation with a multi-cut evaluation.
 */
class PamCutCollection: public PamCut {
public:

  /*! @brief Constructor.
   * The collection can own the cuts, according to the value of the "owns" parameter.
   * If set to true, the collection will take in charge the duty of destroying cuts and
   * freeing their memory; users then should not set owns to true and explicitly call
   * delete for the cuts in the collection. If instead owns is set to false, no destruction
   * is performed by the collection; in this case, the user should issue the eventual
   * delete calls.
   *
   * @param collectionName The collection's name.
   * @param owns If true, the collection will own the cuts, ie., it will
   *             destroy them in its destructor.
   */
  PamCutCollection(const char *collectionName, bool owns = true) :
    PamCut(collectionName), _owns(owns) {
  }

  /*! @brief Destructor. */
  ~PamCutCollection();

  /*! @brief Adds a cut to the cut collection
   *  This routine adds a cut to the collection. These are stored in a vector in the same order
   *  they are inserted (the first cut would be element 0, the second cut element 1 and so on).
   *  All the references to a "cut number" or "cut index" will refer to this numbering scheme.
   *
   * @param cut The pointer to a PamCut-derived object to add to the collection.
   */
  void AddCut(PamCut *cut);

  /*! @brief The basic selection.
   *
   *  Like in the mother class, this method performs a basic check on the current event: it calls
   *  Check() for each cut previously added with AddCut(), exiting if one of them is not satisfied.
   *
   *  @param event The event to analyze.
   *  @return the index of the failed cut (range: [0, \#cuts-1], see AddCut()); #CUTOK if the event
   *  satisfies all the cuts.
   */
  int Check(PamLevel2 *event);

  /*! @brief Applies the cuts to the current event.
   *
   *  This routine works pretty much like the redefinition of Check(), calling ApplyCut() (instead of
   *  Check() )for each cut. If a cut fails, it calls OnBad(), passing the index of the failed cut as
   *  the selectionResult argument. If all the cuts are successful, it calls OnGood().
   *
   * @param event The event to analyze.
   * @return same return values as Check().
   */
  int ApplyCut(PamLevel2 *event);

  /*! @brief Returns a pointer to the iCut-th cut.
   *
   *  The return value of this method is a pointer to a PamCut object; hence, to use the specific method of
   *  derived cuts it must be cast to the proper cut class.
   *
   *  @param iCut The cut number, defined as the insertion order (from 0 to \#cuts-1, see AddCut()).
   *  @return pointer to the iCut-th cut; NULL if the specified cut cannot be found or if no cuts are present.
   * */
  PamCut *GetCut(unsigned int iCut);

  /*! @brief Searches for a cut by name.
   *
   *  The return value of this method is a pointer to a PamCut object; hence, to use the specific method of
   *  derived cuts it must be cast to the proper cut class.
   *
   * @param cutName The name of the cut to search for.
   *  @return pointer to the iCut-th cut; NULL if the specified cut cannot be found or if no cuts are present.
   * */
  PamCut *GetCut(const char *cutName);

  /*! @brief The number of cuts contained in the collection.
   *
   * @return The number of cuts
   */
  unsigned int GetSize();

  /*! @brief The pre-analysis task definition.
   *
   * This override of the Setup() method calls Setup() for the base class PamCut, and subsequently for each cut
   * contained in the collection, in the same order the cuts were added to the collection.
   *
   * @param events The PamLevel2 pointer to the events that will be analyzed. Unused, but required by the interface.
   */
  void Setup(PamLevel2 *events);

  /*! @brief The post-analysis task definition.
   *
   * This override of the Finalize() method calls  PamCut::Finalize() and then the Finalize() method of each cut
   * contained in the collection, in the same order.
   */
  void Finalize();

  /*! @brief Assignment operator redefinition.
   * The assignment operator replaces the content of the LHS with that of RHS. The net effect would be that
   * the cuts contained in the LHS are exactly the same that are in the RHS. In particular, this means that
   * any modification to one of the cuts will propagate both to the LHS and RHS collections. Also the cut
   * name will be copied, since the implementation invokes PamCut::operator=.
   *
   * @param rightValue The RHS.
   * @return The new value for LHS.
   */
  PamCutCollection& operator=(const PamCutCollection &rightValue);

protected:
  /*! @brief A vector containing pointers to PamCut objects */
  std::vector<PamCut*> _cuts;

  /*! @brief A flag signaling if the collection owns the cuts (ie., if the collection
   *         will destroy the cuts.
   */
  bool _owns;
};

#endif /* PAMCUTBASE_H_ */
