#ifndef __JFIT__JENERGY__
#define __JFIT__JENERGY__

#include <cmath>
#include <limits>

#include "JLang/JComparable.hh"
#include "JMath/JMath.hh"


/**
 * \author mdejong
 */

namespace JFIT {}
namespace JPP { using namespace JFIT; }

namespace JFIT {

  using JMATH::JMath;
  using JLANG::JComparable;


  /**
   * Data structure for fit of energy.
   * The internal value is equal to the logarithm of the energy.
   */
  class JEnergy :
    public JMath<JEnergy>,
    public JComparable<JEnergy>
  {
  public:
    /**
     * Default constructor.
     */
    JEnergy() :
      __X(0.0)
    {}


    /**
     * Constructor.
     *
     * \param  X                x-value [log(E/GeV)]
     */
    JEnergy(const double X) :
      __X(X)
    {}


    /**
     * Get Energy.
     *
     * \return                  Energy
     */
    const JEnergy& getEnergy() const
    {
      return static_cast<const JEnergy&>(*this);
    }


    /**
     * Set Energy.
     *
     * \param  energy           Energy
     */
    void setEnergy(const JEnergy& energy)
    {
      static_cast<JEnergy&>(*this) = energy;
    }


    /**
     * Less than method.
     *
     * \param   X               Energy [log(E/GeV)]
     * \return                  true if this energy less than given energy; else false
     */
    bool less(const JEnergy& X) const
    {
      return __X < X.__X;
    }


    /**
     * Prefix unary minus.
     *
     * \return                  Energy
     */
    JEnergy& negate()
    {
      __X = -__X;

      return *this;
    }


    /**
     * Addition operator.
     *
     * \param  value            Energy
     * \return                  Energy
     */
    JEnergy& add(const JEnergy& value)
    {
      __X += value.__X;

      return *this;
    }


    /**
     * Subtraction operator.
     *
     * \param  value            Energy
     * \return                  Energy
     */
    JEnergy& sub(const JEnergy& value)
    {
      __X -= value.__X;

      return *this;
    }


    /**
     * Multiplication operator.
     *
     * \param  value            multiplication factor
     * \return                  Energy
     */
    JEnergy& mul(const double value)
    {
      __X *= value;

      return *this;
    }


    /**
     * Division operator.
     *
     * \param  value            multiplication factor
     * \return                  Energy
     */
    JEnergy& div(const double value)
    {
      __X /= value;

      return *this;
    }


    /**
     * Get energy.
     *
     * \return                  Energy [log(E/GeV)]
     */
    double getlog10E() const
    {
      return __X;
    }


    /**
     * Get energy.
     *
     * \return                  Energy [GeV]
     */
    double getE() const
    {
      return pow(10.0, __X);
    }


    /**
     * Put energy.
     *
     * \param  E                Energy [GeV]
     */
    void putE(const double E)
    {
      __X = log10(E);
    }


    /**
     * Get derivative of energy.
     *
     * \return                  dE/dx [GeV]
     */
    double getDE() const
    {
      return getE() * log(10.0);
    }


    /**
     * Get absolute value.
     *
     * \param  energy           energy
     */
    friend inline double fabs(const JEnergy& energy)
    {
      return std::fabs(energy.__X);
    }


    /**
     * Get minimum possible value.
     *
     * \return                  minimum possible value
     */
    static JEnergy min()
    {
      return JEnergy(std::numeric_limits<double>::lowest());
    }


    /**
     * Get maximum possible value.
     *
     * \return                  maximum possible value
     */
    static JEnergy max()
    {
      return JEnergy(std::numeric_limits<double>::max());
    }


    /**
     * Read object from input.
     *
     * \param  in               input stream
     * \param  object           object
     * \return                  input stream
     */
    friend inline std::istream& operator>>(std::istream& in, JEnergy& object)
    {
      in >> object.__X;

      return in;
    }


    /**
     * Write object to output.
     *
     * \param  out              output stream
     * \param  object           object
     * \return                  output stream
     */
    friend inline std::ostream& operator<<(std::ostream& out, const JEnergy& object)
    {
      out << object.__X;

      return out;
    }


    typedef double JEnergy::*parameter_type;

    static parameter_type pE() { return &JEnergy::__X; }

  protected:
    double __X;
  };
}

#endif