/** \defgroup Computation Mathematical computations */

/** @addtogroup Computation
    @{
*/

/** @file compute.h
    \brief This file contains the definitions of the classes that will
    be used to compute a mathematical expression.

    The base class is CValue, from which other classes are derived.
    First, the COperation class, from which the classes that represent
    different mathematical operations are derived.  Next, the
    classes CVariable and CNumber are derived from the base class.

    Each class contains the Compute() function that returns the value
    of the object.  For operations, it returns the value of the
    operation (addition, for example), on its operands (represented
    by the two pointers.  For numbers or variables, the returned value
    is simply the number itself or the value of x, y or z.
*/

#ifndef COMPUTE_H
#define COMPUTE_H


/**
  \brief This class is the base class from which other classes
  are derived.

  By containing pointers to other CValue objects, it helps
  building a tree representing a mathematical expression.
*/
class CValue
{
 public:
  /**
     This enum represents the variables x, y or z.
  */
  enum TYPE_VARIABLE { TYPE_X, TYPE_Y, TYPE_Z };

  /**
     This pure virtual function returns a copy of the tree
     represented by this object.
  */
  virtual CValue* GetCopy() const = 0;

  /**
     This pure virtual function returns the numerical value 
     of the CValue object.
  */
  virtual float Compute(const CVector3f&) const = 0;

  /**
     This pure virtual function returns a newly allocated
     pointer to the CValue object representing the derivative
     of the object.
  */
  virtual CValue* Derive(TYPE_VARIABLE Type) const = 0;

  /**
     This pure virtual function fills the stream with the expression of
     the CValue object.
  */
  virtual void Print(std::ostream&) const = 0;

  /**
     This pure virtual function fills the vector with code to
     compute the formula.
  */
  virtual void Compile(std::vector<char>& v, int& i) const = 0;

  /**
    Virtual desctructor (for inheritance).
  */
  virtual ~CValue() {};

  static CValue* GetNewAddition(CValue* pLeftOperand, CValue* pRightOperand);
  static CValue* GetNewSubstraction(CValue* pLeftOperand,
                                    CValue* pRightOperand);
  static CValue* GetNewProduct(CValue* pLeftOperand, CValue* pRightOperand);
  static CValue* GetNewDivision(CValue* pLeftOperand, CValue* pRightOperand);
  static CValue* GetNewOpposite(CValue* pLeftOperand);
  static CValue* GetNewSqrt(CValue* pLeftOperand);
  static CValue* GetNewSin(CValue* pLeftOperand);
  static CValue* GetNewCos(CValue* pLeftOperand);
  static CValue* GetNewTan(CValue* pLeftOperand);
  static CValue* GetNewExp(CValue* pLeftOperand);
  static CValue* GetNewLn(CValue* pLeftOperand);
  static CValue* GetNewPow(CValue* pLeftOperand, CValue* pRightOperand);

  /**
     This function is used to know if the object can be evaluated
     to a constant.  It is overloaded only in the CNumber class,
     where Number is set to the value of the object.
  */
  virtual bool IsConstant(float* pNumber = NULL) const 
    { return false; }

 protected:
  /**
     This function is used to know if the object is the absorbing
     element of the multiplication, which is 0.  It is overloaded
     only in the CNumber class.
  */
  virtual bool IsMultAbsorbElem() const { return false; }

  /**
     This function is used to know if the object is the neutral
     element of the multiplication, which is 1.  It is overloaded
     only in the CNumber class.
  */
  virtual bool IsMultNeutralElem() const { return false; }

  /**
     This function is used to know if the object is the neutral
     element of the addition, which is 0.  It is overloaded
     only in the CNumber class.
  */
  virtual bool IsAddNeutralElem() const { return false; }

};



/**
   \brief This class is the base class for mathematical operations.
*/
class COperation : public CValue
{
 public:
  /**
     COperation simple constructor.
  */
  COperation(CValue* pLeftOperand, CValue* pRightOperand)
    { m_pLeftOperand = pLeftOperand; m_pRightOperand = pRightOperand; }

  /**
     This pure virtual function returns a copy of the tree
     represented by this object.
  */
  virtual CValue* GetCopy() const = 0;

  /**
     This pure virtual function returns the numerical value 
     of the CValue object.
  */
  virtual float Compute(const CVector3f& Point) const = 0;

  /**
     This pure virtual function returns a newly allocated
     pointer to the CValue object representing the derivative
     of the object.
  */
  virtual CValue* Derive(TYPE_VARIABLE Type) const = 0;

  /**
     This function fills the stream with the expression of
     the CValue object.
  */
  virtual void Print(std::ostream&) const = 0;

  /**
     This pure virtual function fills the vector with code to
     compute the formula.
  */
  virtual void Compile(std::vector<char>& v, int& i) const = 0;

  /**
     The desctructor of the COperation objects.
  */
  virtual ~COperation()
    {
      if (m_pLeftOperand)
        delete m_pLeftOperand;
      if (m_pRightOperand)
        delete m_pRightOperand;
    }

 protected:
  CValue* m_pLeftOperand;  /**< Pointer to the left operand. */
  CValue* m_pRightOperand; /**< Pointer to the right operand. */
};


/**
   \brief This class represents addition.
*/
class CAddition : public COperation
{
 public:
  CAddition(CValue* pLeftOperand, CValue* pRightOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents substraction.
*/
class CSubstraction : public COperation
{
 public:
  CSubstraction(CValue* pLeftOperand, CValue* pRightOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents product.
*/
class CProduct : public COperation
{
 public:
  CProduct(CValue* pLeftOperand, CValue* pRightOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents division.
*/
class CDivision : public COperation
{
 public:
  CDivision(CValue* pLeftOperand, CValue* pRightOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents the unary minus.
*/
class COpposite : public COperation
{
 public:
  COpposite(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};


/**
   \brief This class represents square root.
*/
class CSqrt : public COperation
{
 public:
  CSqrt(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents sine.
*/
class CSin : public COperation
{
 public:
  CSin(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents cosine.
*/
class CCos : public COperation
{
 public:
  CCos(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents tangent.
*/
class CTan : public COperation
{
 public:
  CTan(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief this class respresents exponential.
*/
class CExp : public COperation
{
 public:
  CExp(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief this class respresents natural logarithm.
*/
class CLn : public COperation
{
 public:
  CLn(CValue* pLeftOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};

/**
   \brief This class represents exposants.
*/
class CPow : public COperation
{
 public:
  CPow(CValue* pLeftOperand, CValue* pRightOperand);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;
};



/**
   \brief This class represents a variable.

   It can be either x, y or z.
*/
class CVariable : public CValue
{
 public:
  CVariable(TYPE_VARIABLE Type);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;

 private:
  TYPE_VARIABLE m_Type; /**< Number representing the ID of the variable. */
};


/**
   \brief This class represents a constant floating point number.
*/
class CNumber : public CValue
{
 public:
  CNumber(float Number);
  virtual CValue* GetCopy() const;
  virtual float Compute(const CVector3f& Point) const;
  virtual CValue* Derive(TYPE_VARIABLE Type) const;
  virtual void Print(std::ostream& o) const;
  virtual void Compile(std::vector<char>& v, int& i) const;

  /**
     This function is used to know if the object can be evaluated
     to a constant.
  */
  virtual bool IsConstant(float* pNumber = NULL) const
    {
      if (pNumber)
        *pNumber = m_Number;

      return true;
    }

 protected:
  /**
     This function is used to know if the objet is the absorbing
     element of the multiplication, which is 0.  It is overloaded
     only in the CNumber class.
  */
  virtual bool IsMultAbsorbElem() const { return m_Number == 0; }

  /**
     This function is used to know if the objet is the neutral
     element of the multiplication, which is 1.  It is overloaded
     only in the CNumber class.
  */
  virtual bool IsMultNeutralElem() const { return m_Number == 1; }

  /**
     This function is used to know if the objet is the neutral
     element of the addition, which is 0.  It is overloaded
     only in the CNumber class.
  */
  virtual bool IsAddNeutralElem() const { return m_Number == 0; }

 private:
  float m_Number; /**< A numerical constant. */
};


#endif  // COMPUTE_H

/** @} */
