/* massXpert - the true massist's program.
   --------------------------------------
   Copyright(C) 2006,2007 Filippo Rusconi

   http://www.massxpert.org/massXpert

   This file is part of the massXpert project.

   The massxpert project is the successor to the "GNU polyxmass"
   project that is an official GNU project package(see
   www.gnu.org). The massXpert project is not endorsed by the GNU
   project, although it is released ---in its entirety--- under the
   GNU General Public License. A huge part of the code in massXpert
   is actually a C++ rewrite of code in GNU polyxmass. As such
   massXpert was started at the Centre National de la Recherche
   Scientifique(FRANCE), that granted me the formal authorization to
   publish it under this Free Software License.

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

   This software 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 software; if not, write to the

   Free Software Foundation, Inc.,

   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/


#ifndef FORMULA_HPP
#define FORMULA_HPP


/////////////////////// Qt includes
#include <QString>


/////////////////////// Local includes
#include "atomCount.hpp"


namespace massXpert
{

  enum MxtFormulaSplit
    {
      MXT_FORMULA_SPLIT_FAIL = 1 << 0,
      MXT_FORMULA_SPLIT_PLUS = 1 << 1,
      MXT_FORMULA_SPLIT_MINUS = 1 << 2,
      MXT_FORMULA_SPLIT_BOTH = 
     (MXT_FORMULA_SPLIT_PLUS | MXT_FORMULA_SPLIT_MINUS),
    };



  //! The Formula class provides a formula(or action-formula).
  /*! A formula is the description of the atomic composition of a
    compound. For example, "C2H6" is a formula. An action-formula is not
    a static formula(like "C2H6" is) but a set of formulas in
    association with actions(which is why an action-formula best
    accounts for a reaction). For example, acetylation of a molecule can
    be represented using this action-formula: "-H+CH3CO". The formula
    associated with the '-' action accounts for the leaving group of the
    reaction, while the formula associated with the '+' action accounts
    for the arriving group of the reaction.
  
    Note that there is no limitation on the amount of such actions, as
    one could have an action formula like this "-H+CO2-H20+C2H6".

    A formula and an action-formula behave exactly the same from an
    end-user perspective. When created, a Formula has its formula
    string contain the formula(be it a pure formula or an
    action-formula). Behind the scenes, functions are called to separate
    all the '+'-associated formulas from all the '-'-associated formulas
    so that masses are correctly associated to each "leaving" or
    "arriving" action. Formulas that are '-'-associated are stored in
    the so-called "minus-formula", while '+'-associated ones are stored
    in the "plus-formula"(all QString objects).

    Upon parsing of the formula the minus-formula and the plus-formula
    are populated with formulas(in the example above, minus-formula
    would contain "HH20" while plus-formula would contain "CO2C2H6") and
    these are next used to create AtomCount objects that are stored
    in the list of atomcount objects with which the accounting of the
    masses of the formula is performed.
  */
  class Formula
  {
  protected:
    //! Formula or action-formula.
    /*! This formula or action-formula is not processed, this is always
      the original formula with which a Formula instance is
      created.
    */
    QString m_formula;
  
    //! Plus-formula(or '+'-associated formula). 
    /*! After parsing of an action-formula, all its '+' components are
      stored in this member.
    */
    QString m_plusFormula;

    //! Minus-formula(or '-'-associated formula). 
    /*! After parsing of an action-formula, all its '-' components are
      stored in this member.
    */
    QString m_minusFormula;

    //! List of dynamically allocated AtomCount objects.
    /*! This list stores all the AtomCount objects that are created
      upon parsing of the formula.
    */
    QList<AtomCount *> m_atomCountList;
  
    void setPlusFormula(const QString &);
    const QString &plusFormula() const;

    void setMinusFormula(const QString &);
    const QString &minusFormula() const;

    int removeTitle();
    int removeSpaces();
      
    int splitParts(const QList<Atom *> &,
		    int = 1, 
		    bool = false, 
		    bool = false);
  
    bool parse(const QList<Atom *> &,
		const QString &, 
		int = 1, 
		bool = false, 
		bool = false);

    int accountInList(const AtomCount &, int = 1);

  public:
    Formula(const QString & = QString());
    Formula(const Formula &);

    virtual ~Formula();

    virtual Formula * clone() const;
    virtual void clone(Formula *) const;
    virtual void mold(const Formula &);
    virtual Formula & operator =(const Formula &);

    void setFormula(const QString &);
    void setFormula(const Formula &);
    QString text() const;

    void clear();
    
    int accountInList(const QString &, const QList<Atom *> &, int = 1);
      
    const QList<AtomCount *> &atomCountList() const;

    virtual bool operator ==(const Formula &) const;
    virtual bool operator !=(const Formula &) const;

    QChar actions(const QString &) const;
    QChar actions() const;
  
    static bool checkSyntax(const QString &);
    bool checkSyntax();

    virtual bool validate(const QList<Atom *> &, 
			   bool = false, bool = false);
  
    virtual bool accountMasses(const QList<Atom *> &,
				double * = 0, double * = 0, int = 1);

    virtual bool accountMasses(const QList<Atom *> &,
				Ponderable *, int = 1);
    bool accountAtoms(const QList<Atom *> &, int);
    QString elementalComposition() const;

    int totalAtoms() const;
    int totalIsotopes(const QList<Atom *> &refList) const;
    bool totalEntities(const QList<Atom *> &refList, 
			int * = 0, int * = 0) const;
  
    bool deepAtomCopy(const QList<Atom *> &refList);

    bool renderXmlFormulaElement(const QDomElement &);
  };

} // namespace massXpert


#endif // FORMULA_HPP

 
