/* This file is part of the KDE project
   Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#ifndef KSPREAD_FORMULA
#define KSPREAD_FORMULA

#include <tqstring.h>
#include <tqvaluevector.h>

class TDELocale;

namespace KSpread
{
class Cell;
class Sheet;
class Value;

/**
 * Token
 */
class Token
{
  public:
    /**
     * token types
     */
    enum Type
    {
      Unknown = 0, ///< unknown type
      Boolean,     ///< True, False (also i18n-ized)
      Integer,     ///< 14, 3, 1977
      Float,       ///< 3.141592, 1e10, 5.9e-7
      String,      ///< "KOffice", "The quick brown fox..."
      Operator,    ///< +, *, /, -
      Cell,        ///< $A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum
      Range,       ///< C1:C100
      Identifier   ///< function name or named area
    };

    /**
     * operator types
     */
    enum Op
    {
      InvalidOp = 0,  ///< invalid operator
      Plus,           ///<  + (addition)
      Minus,          ///<  - (substraction, negation)
      Asterisk,       ///<  * (multiplication)
      Slash,          ///<  / (division)
      Caret,          ///<  ^ (power)
      LeftPar,        ///<  (
      RightPar,       ///<  )
      Comma,          ///<  ,
      Semicolon,      ///<  ; (argument separator)
      Ampersand,      ///<  & (string concat)
      Equal,          ///<  =
      NotEqual,       ///<  <>
      Less,           ///<  <
      Greater,        ///<  >
      LessEqual,      ///<  <=
      GreaterEqual,   ///<  >=
      Percent         ///<  %
    };

    /**
     * Creates a token.
     */
    Token( Type type = Unknown, const TQString& text = TQString(), int pos = -1 );

    static const Token null;

    Token( const Token& );
    Token& operator=( const Token& );

    /**
     * Returns type of the token.
     */
    Type type() const { return m_type; }

    /**
     * Returns text associated with the token.
     *
     * If you want to obtain meaningful value of this token, instead of
     * text(), you might use asInteger(), asFloat(), asString(), sheetName(),
     * etc.
     */
    TQString text() const { return m_text; }

    int pos() const { return m_pos; };

    /**
     * Returns true if token is a boolean token.
     */
    bool isBoolean() const { return m_type == Boolean; }

    /**
     * Returns true if token is a integer token.
     */
    bool isInteger() const { return m_type == Integer; }

    /**
     * Returns true if token is a floating-point token.
     */
    bool isFloat() const { return m_type == Float; }

    /**
     * Returns true if token is either integer or floating-point token.
     */
    bool isNumber() const { return (m_type == Integer) || (m_type == Float); }

    /**
     * Returns true if token is a string token.
     */
    bool isString() const { return m_type == String; }

    /**
     * Returns true if token is an operator token.
     */
    bool isOperator() const { return m_type == Operator; }

    /**
     * Returns true if token is a cell reference token.
     */
    bool isCell() const { return m_type == Cell; }

    /**
     * Returns true if token is a range reference token.
     */
    bool isRange() const { return m_type == Range; }

    /**
     * Returns true if token is an identifier.
     */
    bool isIdentifier() const { return m_type == Identifier; }

    /**
     * Returns boolean value for an boolean token.
     * For any other type of token, return value is undefined.
     */
    bool asBoolean() const;

    /**
     * Returns integer value for an integer token.
     * For any other type of token, returns 0.
     */
    long asInteger() const;

    /**
     * Returns floating-point value for a floating-point token.
     * For any other type of token, returns 0.0.
     */
    double asFloat() const;

    /**
     * Returns string value for a string token.
     * For any other type of token, it returns TQString().
     *
     * Note that token text for a string token still has leading and trailing
     * double-quotes, i.e for "KOffice", text() return "KOffice"
     * (with the quotes, 9 characters) while asString() only return KOffice
     * (without quotes, 7 characters).
     */
    TQString asString() const;

    /**
     * Returns operator value for an operator token.
     * For any other type of token, returns Token::InvalidOp.
     */
    Op asOperator() const;

    /**
     * Returns sheet name in a cell reference token.
     * For any other type of token, it returns TQString().
     *
     * If the cell reference doesn't specify sheet name, an empty string
     * is returned. As example, for "Sheet1!B3" , sheetName() returns
     * "Sheet1" while for "A2" sheetName() returns "".
     *
     * When sheet name contains quotes (as if the name has spaces) like
     * in "'Sales Forecast'!F4", sheetName() returns the name
     * without the quotes, i.e "Sales Forecast" in this case.
     */
    TQString sheetName() const;

    /**
     * Returns a short description of the token.
     * Should be used only to assist debugging.
     */
    TQString description() const;

  protected:

    Type m_type;
    TQString m_text;
    int m_pos;

};

/**
 * Class Tokens represents array of tokens.
 *
 */
class Tokens: public TQValueVector<Token>
{
public:
  Tokens(): TQValueVector<Token>(), m_valid(true) {};
  bool valid() const { return m_valid; }
  void setValid( bool v ){ m_valid = v; }
protected:
  bool m_valid;
};


/**
 * Class Formula encapsulates a formula for a cell.
 *
 * A Formula is a equations which perform calculations on values in the cells
 * and sheets. Every formula must start with an equal sign (=).
 *
 *
 */
class Formula
{
  public:

    /**
     * Creates a formula. It must be owned by a sheet, and optionally sheet.
     */
    Formula (Sheet *sheet,  Cell *cell = 0);

    /**
     * Creates a formula that is not owned by any sheet.
     * This might be useful in some cases.
     */
    Formula();

    /**
     * Destroys the formula.
     */
    ~Formula();

    /**
     * Returns the cell which owns this formula.
     */
    Sheet* sheet() const;
    /**
     * Returns the cell which owns this formula.
     */
    Cell* cell() const;

    /**
     * Sets the expression for this formula.
     */
    void setExpression( const TQString& expr );

    /**
     * Gets the expression of this formula.
     */
    TQString expression() const;

    /**
     * Clears everything, makes as like a newly constructed formula.
     */
    void clear();

    /**
     * Returns true if the specified expression is valid, i.e. it contains
     * no parsing error.
     * Empty formula (i.e. without expression) is always invalid.
     */
    bool isValid() const;

    /**
     * Returns list of tokens associated with this formula. This has nothing to
     * with the formula evaluation but might be useful, e.g. for syntax
     * highlight or similar features.
     * If the formula contains error, the returned tokens is invalid.
     */
    Tokens tokens() const;

    /**
     * Evaluates the formula and returns the result.
     */
    Value eval() const;

    /**
     * Given an expression, this function separates it into tokens.
     * If the expression contains error (e.g. unknown operator, string no terminated)
     * this function returns tokens which is not valid.
     */
    Tokens scan( const TQString& expr, TDELocale* locale = 0 ) const;

    TQString dump() const;

  protected:

    void compile( const Tokens& tokens ) const;

    /**
     * helper function: return true for valid named area
     */
    bool isNamedArea( const TQString& expr ) const;

  private:
    class Private;
    Private *d;
    // no copy or assign
    Formula( const Formula& );
    Formula& operator=( const Formula& );
};

/**
 * Dumps the formula, should be used only to assist debugging.
 */
TQTextStream& operator<<( TQTextStream& ts, Formula formula );


/**
 * helper function: return operator of given token text
 * e.g. "*" yields Operator::Asterisk, and so on
 */
Token::Op matchOperator( const TQString& text );

/**
 * helper function: return true for valid identifier character
 */
bool isIdentifier( TQChar ch );

} // namespace KSpread



#endif // KSPREAD_FORMULA

