/*
 * TrkNucleiZCut.h
 *
 *  Created on: 10-mag-2009
 *      Author: Nicola Mori
 */

/*! @file TrkNucleiZCut.h The TofNucleiZCut class definition file */

#ifndef NO_TRKNUCLEI

#ifndef TRKNUCLEIZCUT_H_
#define TRKNUCLEIZCUT_H_

#include "../../PamCutBase/PamCutBase.h"
#include <TrkNuclei.h>

#include <TH2F.h>

/*! @enum TrkNucleiZ_Return Return values for rejected events */
enum TrkNucleiZ_Return {
  TRKNUCLEIZ_OUTOFBOUNDS, ///< Discarded because charge is out of bounds
  TRKNUCLEIZ_TOOFEWLAYERS, ///< Discarded because charge can be measured in too few layers.
  TRKNUCLEIZ_ILLEGALZ
///< Discarded because charge is not between 1 and 8
};

/*! @enum TrkNucleiZ_method Method to use to measure Z. */
enum TrkNucleiZ_method {
  TRKNUCLEIZ_BETA, ///< Tracker dE/dx Vs. ToF beta
  TRKNUCLEIZ_DEFL,
///< Tracker standalon e: dE/dx Vs. deflection
};

/*! @enum TrkNucleiZ_CheckMean Handy aliases to set check mean */
enum TrkNucleiZ_CheckMean {
  TRKNUCLEIZ_CHECKMEAN, ///< Check the mean value.
  TRKNUCLEIZ_CHECKSINGLEVALUES
///< Check each single charge from each layer.
};

/*! @brief The TrkNuclei charge cut.
 *
 * This cut uses the TrkNuclei library to cut events depending on particle's charge value.
 *
 */

class TrkNucleiZCut: public PamCut {

public:
  /*! @brief Constructor.
   *
   * The charge to look for is passed to the TrkNucleiZCut object as Z. For each charge, there is an associated distribution of
   * events, with mean Zmean and standard deviation sigmaZ. These values will be used to check the events.
   *
   * @param cutName The cut's name.
   * @param Z The charge value.
   * @param lowerLimit The lower bound (in units of sigma_Z) of the desired charge range, defined as Zmean - lowerBound*sigmaZ.
   * @param upperLimit The upper bound (in units of sigma_Z) of the desired charge range, defined as Zmean + upperBound*sigmaZ.
   * @param minLayers The minimum required number of layers which give a valid charge information.
   * @param checkMean Flag to set the check method (see #Check and #TrkNucleiZ_CheckMean).
   * @param method The method to use to measure the particle's charge (see #TrkNucleiZ_method).
   * @return
   */
  TrkNucleiZCut(const char *cutName, unsigned int Z, float lowerLimit, float upperLimit, unsigned int minLayers = 1,
      unsigned int howToCheck = TRKNUCLEIZ_CHECKMEAN, unsigned int method = TRKNUCLEIZ_DEFL) :
    PamCut(cutName), _Z(Z), _lowerLimit(lowerLimit), _upperLimit(upperLimit), _trkNuclei(NULL), _minLayers(minLayers),
        _howToCheck(howToCheck), _method(method) {

  }
  /*! @brief Destructor. */
  ~TrkNucleiZCut() {
    delete _trkNuclei;
  }

  /*! @brief The TrkNucleiZ check.
   *
   * The routine selects events whose value of Zmean obtained from the TrkNuclei Class is in the range [Zmean - sigma*lowerBound, Zmean + sigma*upperBound].
   * Zmean and sigma are defined respectively as the mean and the standard deviation of the charge distributions obtained using TrkNuclei.
   * In current implementation, means are taken to be equal to the charge value (Zmean = Z) and sigmas are:
   *
   *   Z |  sigma
   *   -----------
   *   1 |  0.09
   *   2 |  0.10
   *   3 |  0.17
   *   4 |  0.34
   *   5 |  0.44
   *   6 |  0.59
   *
   * independent of the method used. The TofNuclei calibrations used are the standard ones (from Wolfgang, see TrkNuclei.cpp).
   * First of all, the number of layers giving a valid charge information is checked to be greater than minLayers; if it's not so,
   * the routine will return #TRKNUCLEIZ_TOOFEWLAYERS. Next, it will check if the charge obtained considering the mean dE/dx in the tracker's
   * layers is in the validity range if the constructor's flag howToCheckMean was set to TRKNUCLEIZ_CHECKMEAN; otherwise, it will check each
   * single valid charge value (mean for X and Y views) obtained from each layer. In the latter case, it will return #CUTOK only if all
   * valid layers (ie., those tagged as good for both X and Y in traccker level 2 routines) give a charge inside the bounds, regardless of
   * the value of minLayers.
   *
   * @param event The event to analyze.
   * @return #CUTOK if the charge from mean dE/dx(if howToCheck == #TRKNUCLEIZ_CHECKMEAN) or all the single layer charges
   *         (if howToCheck == #TRKNUCLEIZ_CHECKSINGLEVALUES) obtained from TrkNuclei are in the range [Z - sigma*lowerBound, Z + sigma*upperBound].
   * @return #TRKNUCLEIZ_OUTOFBOUNDS if the charge from mean dE/dx(if howToCheck == #TRKNUCLEIZ_CHECKMEAN) or at least one valid single layer
   *         charge (if howToCheck == #TRKNUCLEIZ_CHECKSINGLEVALUES) is out of bounds.
   * @return #TRKNUCLEIZ_TOOFEWLAYERS if charge information is available for a number of layers lesser than minLayers.
   * @return #TRKNUCLEIZ_OUTOFBOUNDS if Z < 1 or Z > 6.
   *
   */
  int Check(PamLevel2 *event);

private:

  unsigned int _Z;
  static const float _sigmaZ[];

  float _lowerLimit;
  float _upperLimit;
  TrkNuclei *_trkNuclei;
  unsigned int _minLayers;
  unsigned int _howToCheck;
  unsigned int _method;
};
#endif /* TRKNUCLEIZCUT_H_ */

#endif /* NO_TRKNUCLEI */
