/** \defgroup Computation Mathematical computations */

/** @addtogroup Computation
    @{
*/

/** @file CMathExpression.h
    \brief This file contains the definition of the class that will
    represent a mathematical expression.

    It actually contains a CValue pointer and offers a few functions.
*/

#ifndef CMATHEXPRESSION_H
#define CMATHEXPRESSION_H


/**
   \brief This class represents a mathematical expression.

   It is actually the only class that will be directly called and used
   to calculate something.
*/

class CMathExpression
{
 public:
  /**
     \brief This is the CMathExpression constructor.
  */
  CMathExpression(const char * Equation = 0);

  /**
     \brief This is the CMathExpression copy constructor.
  */
  CMathExpression(const CMathExpression& copy)
    { m_pFormula = copy.m_pFormula->GetCopy(); }

  /**
     \brief This is the assignment operator.
  */
  const CMathExpression& operator=(const CMathExpression& copy)
    {
      if (this != &copy)
        {
          if (m_pFormula)
            delete m_pFormula;

          m_pFormula = copy.m_pFormula->GetCopy();
        }
      return *this;
    }

  /**
     This function returns the value of the expression it contains
     evaluated at a specific point.
  */
  float GetValue(const CVector3f& Point) const 
    {
      // To be able to switch between run-time generated code
      // and tree-based evaluation
#if 0
      POP_ASSERT(m_pFormula != NULL, "Using a NULL pointer.");
      return (m_pFormula->Compute(Point));
#else
      POP_ASSERT(m_pFunction != NULL, "Using a NULL pointer.");
      return ((*m_pFunction)(Point));
#endif
    }

  /**
     This function returns a pointer to a newly allocated expression
     containing the derivative of the expression.
  */
  CMathExpression* GetDerivative(CValue::TYPE_VARIABLE Type) const
    { 
      POP_ASSERT(m_pFormula != NULL, "Using a NULL pointer.");
      CMathExpression* ptrDerivative = new CMathExpression;
      ptrDerivative->m_pFormula = m_pFormula->Derive(Type);
      ptrDerivative->Compile();
      return ptrDerivative;
    }

  /**
     This function fills the stream with the expression of
     the CValue it contains.
  */
  void Print(std::ostream& o) const
    {
      POP_ASSERT(m_pFormula != NULL, "Using a NULL pointer.");
      m_pFormula->Print(o);
    }

  /**
     This function returns a string representing the formula it holds
  */
  std::string GetString() const
    {
      POP_ASSERT(m_pFormula != NULL, "Using a NULL pointer.");
      std::ostringstream o;
      m_pFormula->Print(o);
      return o.str();
    }

  /**
     Destructor of CMathExpression, which release the memory
     in the CValue object it contains.
  */
  ~CMathExpression()
    {
      if (m_pFormula)
        delete m_pFormula;
      if (m_pFunction)
        delete [] (char *) m_pFunction;
    }

  /**
     \brief This recursive function validates an equation.
  */
  static bool Validate(const std::string& Formula, int *value = NULL,
                       int min = -1, int max = -1);

 private:
  CValue* m_pFormula; /**< Pointer to the first node of the expression */
  float (*m_pFunction)(const CVector3f&); /**< Pointer to the executable
                                               function */


  /**
     \brief This recursive function is used to build the tree
     associated with a mathematical expression.
  */
  static CValue* BuildFormula(const char* Formula, int min, int max);

  /**
     \brief This function fills the vector with code to compute
     the given formula.
  */
  void Compile(std::vector<char>& v) const;

  /**
     \brief This function updates the pointer to the function
     that computes the given formula.
  */
  void Compile()
    {
      if (m_pFunction)
        delete [] (char *) m_pFunction;

      // Compilation of the calculation function
      std::vector<char> buffer;
      Compile(buffer);
      char * pFunc = new char[buffer.size()];
      memcpy(pFunc, &buffer[0], buffer.size()*sizeof(char));
      m_pFunction = (float (*)(const CVector3f&)) pFunc;
    }
};

#endif  // CMATHEXPRESSION_H

/** @} */
