// -*- C++ -*-
#ifndef RIVET_BeamThrust_HH
#define RIVET_BeamThrust_HH

#include "Rivet/Projection.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Event.hh"

namespace Rivet {


  /// Calculator of the beam-thrust observable
  class BeamThrust : public Projection {
  public:

    /// Constructor.
    BeamThrust() {}

    BeamThrust(const FinalState& fsp) {
      setName("BeamThrust");
      declare(fsp, "FS");
    }

    /// Clone on the heap.
    RIVET_DEFAULT_PROJ_CLONE(BeamThrust);

    /// Import to avoid warnings about overload-hiding
    using Projection::operator =;


  protected:

    /// Perform the projection on the Event
    void project(const Event& e) {
      const vector<Particle> ps
        = apply<FinalState>(e, "FS").particles();
      calc(ps);
    }

    /// Compare projections
    CmpState compare(const Projection& p) const {
      return mkNamedPCmp(p, "FS");
    }

  public:

    double beamthrust() const { return _beamthrust; }

    /// @name Direct methods
    /// Ways to do the calculation directly, without engaging the caching system
    /// @{

    /// Manually calculate the beamthrust, without engaging the caching system
    void calc(const FinalState& fs);

    /// Manually calculate the beamthrust, without engaging the caching system
    void calc(const vector<Particle>& fsparticles);

    /// Manually calculate the beamthrust, without engaging the caching system
    void calc(const vector<FourMomentum>& fsmomenta);

    /// @}


  protected:

    /// The beamthrust scalar.
    double _beamthrust;


  protected:

    /// Explicitly calculate the beamthrust values.
    void _calcBeamThrust(const vector<FourMomentum>& fsmomenta);

  };

}

#endif
