
/*  wxEcMath - version 0.6.3
 *  Copyright (C) 2008-2010, http://sourceforge.net/projects/wxecmath/
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/**
 * \file ec_engine.h
 * \brief Contains the mathematical interpreter
 * \author ecrucru
 * \version 0.6.3
 * \date August 2008
 *
 * The only class defined here is wxEcEngine and does not derive from another class.
 */

#ifndef ec_engine_h
#define ec_engine_h

//------------------------------------------

#include "wx/wxprec.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include "wx/hashmap.h"
#include "ec_defs.h"

//------------------------------------------

/** \class wxEcEngine
 *  \brief Evaluates mathematical expressions.
 *
 * When the object is created, the radian mode is activated and you can compute directly.
 * To do it, see the sample written on the main page of this documentation.
 */
class WXDLLEXPORT wxEcEngine
{

    private:
        #ifdef wxECM_USEDEBUG
            wxArrayString m_debugoutput;
            void LogAction(wxString message, bool verbose = false);
        #endif

        int m_trigomode, m_errorcode;
        size_t m_offset;
        wxString m_formula, m_indicator;
        wxEcConstMap m_constants;
        double m_lastresult, m_pool[wxECD_STACKMAX+1], m_antecomp[wxECD_STACKMAX+1];
        bool m_internallog;

        wxEcPosition BracketLookup(wxString *expression);
        wxUint32 CountChar(wxString *input, wxChar what);
        double ConvertToRadian(double angle);
        long FindConstant(wxString name);
        long FindOperator(wxString *expression);
        unsigned long Function2ID(wxString *function);
        wxString FunctionLookUp(wxString *expression, size_t bracketPosition);
        bool IsOperator(wxString *expression, size_t charPosition);
        bool IsParitySign(wxString *expression, size_t charPosition);
        void LeftPool(int offset);
        long NextOperator(wxString *expression, size_t charPosition = -1);

        double evalf(wxString *expression);
        double evalexp(wxString *expression);
        bool StackIt(double *value);

    public:
        #ifdef wxECM_USEDEBUG
            /** Returns the log generated by the evaluation of the formula.
             *  \remarks This function is only available if \a wxECM_USEDEBUG is defined.
             *           To use it, code like this :
             *              \code
             * #ifdef wxECM_USEDEBUG
             * wxArrayString myLog = myEngine->GetLog();
             * #endif
             *              \endcode
             *  \see wxECM_USEDEBUG
             */
            wxArrayString GetLog();
        #endif

        /** The default constructor which takes no parameter.
         */
        wxEcEngine();
        /** The default destructor.
         */
        ~wxEcEngine();
        /** Reads the formula currently stored by the object.
         * \see SetFormula()
         */
        wxString GetFormula();
        /** Returns the tip associated with the latest error. It helps you to track down a problem
         *  when GetLastError() does not return \a wxECE_NOERROR.
         */
        wxString GetIndicator();
        /** Returns the latest error obtained with Compute().
         * \return \a wxECE_NOERROR if no error occured.
         * \see ec_defs.h
         * \see GetIndicator()
         * \see TranslateError()
         */
        int GetLastError();
        /** Returns the latest result obtained with Compute().
         * \see GetLastError()
         */
        double GetLastResult();
        /** Returns a string describing the meaning of an error code.
         * \param code An error code defined in ec_defs.h (wxECE_*).
         */
        wxString TranslateError(int code);
        /** Returns the trigonometric mode used for cosine, sine and tangent.
         * \return The current mode. wxECA_RADIAN should be the default value.
         * \see ec_defs.h
         */
        int GetTrigonometricMode() { return m_trigomode; }
        /** Sets the trigonometric mode to be used for cosine, sine and tangent.
         * \param trigmode A mode defined in ec_defs.h (wxECA_*).
         */
        void SetTrigonometricMode(int trigmode) { m_trigomode = trigmode; }
        /** Resets the engine.
         * \param formulaToo Will clear the formula set with SetFormula().
         * \param constantsToo Will restaure the default constants.
         */
        void Reset(bool formulaToo, bool constantsToo);

        /** Deletes a constant.
         * \param name The name of the constant.
         * \return \a true on success, \a false on failure.
         */
        bool DeleteConstant(wxString name);
        /** Converts a constant or a floating number encoded as a wxString, and stores it into the \a destination.
         * \param expression Input to convert.
         * \param destination Pointer to a double where to store the value.
         * \return \a true if the constant is found and converted, \a false if it is neither a valid constant nor a floating number.
         * \remarks This function can be seen as a "wxString to Double converter". If wxString is the name
         *          of a constant, it will look for its value. Else it tries to convert into double in the destination.
         */
        bool GetConstant(wxString expression, double *destination);
        /** Gives the number of constants currently defined.
         */
        int GetConstantCount();
        /** Makes a dump of all the constants into a \a wxControlWithItems, it can be \a wxListBox, \a wxComboBox...
         * \param destination A pointer to the control which will receive the data.
         * \return \a true on success, \a false on failure.
         * \remarks If the result is \a true, it does not presume that at least 1 item has been added.
         *          You have to make sure on your own.
         */
        bool ListAllConstants(wxControlWithItems *destination);
        /** Defines a new constant. If the constant already exists, it will be overwritten.
         * \param name The name of the new constant.
         * \param value The value of the new constant.
         * \return \a true if the constant has been (re)defined, \a false on failure.
         */
        bool SetConstant(wxString name, wxDouble value);
        /** Deletes all the constants, and sets the default ones.
         */
        void ResetConstants();

        /** Applies a function on the given value.
         * \param function The pointer to the name of the function.
         * \param value The pointer to the value which will be read and overwritten.
         * \return \a true on success, \a false if the function is unknown or not defined for the given value.
         */
        bool ApplyFunction(wxString *function, double *value);
        /** Evaluates the mathematical expression you have set with SetFormula(). To be sure of the result
         *  you must call GetLastError().
         * \return The result of the computation. Zero is the default value if it failed.
         * \see GetLastResult()
         */
        double Compute();
        /** Performs an approximation of the derivative of the loaded expression at a given point.
         * \param where The X-coordinate which must be evaluated.
         * \param result The pointer to the floating number which will contain df(x)/dx. It must be valid.
         * \param storewhere A pointer to store f(x) as a floating number.
         * \return \a true on success, \a false on failure (see GetLastError() to know more about).
         * \see wxEcEngine::SetFormula()
         * \see wxECD_DXSTEP
         */
        bool Derivate(double where, double *result, double *storewhere = NULL);
        /** Checks the validity of an expression. The method is based on a set of criteria, such as
         *  the number of brackets. The symbols used in the expression will not be validated.
         * \param expression A pointer to the expression to check.
         * \return \a true if the expression appears logically correct, \a false in the other cases.
         */
        bool IsValid(wxString *expression);
        /** Stores the internal formula which will be used for all the computations.
         * If the formula is rejected, wxECE_SYNTAX will be returned by GetLastError().
         * \remarks The expression will be simplified and checked before being stored.
         * \param expression The formula you want to use.
         * \return \a true if the formula is accepted, \a false if it is rejected.
         */
        bool SetFormula(wxString expression);
        /** Performs the simplifications required to make the expression readable by the interpreter.
         *  You cannot expect all inputs to be valid after this operation. It depends on the quality
         *  of the input (in terms of wrong syntax).
         * \param expression A pointer to a string which will be read and rewritten.
         */
        void Simplify(wxString *expression);
        /** Enables or disable the storage of debug information in LogAction().
         *  This function is useless if \a wxECM_USEDEBUG is not defined.
         * \see wxECM_USEDEBUG
         * \see wxEcEngine::LogAction()
         */
        void UseDebug(bool state) { m_internallog = state; }
};

#endif
