/* 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 POLYMER_HPP
#define POLYMER_HPP


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


/////////////////////// Local includes
#include "sequence.hpp"
#include "ionizable.hpp"
#include "polChemDef.hpp"
#include "modif.hpp"
#include "calcOptions.hpp"
#include "crossLinkList.hpp"


namespace massXpert
{

  //! The Polymer class provides a polymer.
  /*! A polymer is a sequence(Sequence) to which data are
    aggregated to make it able to perform a number of tasks. 

    The polymer has a name and a code, so that it is possible to
    refer to it in printed material...

    Because Polymer derives from Ionizable, which itself derives from
    PolChemDefEntity, it holds a pointer to the polymer chemistry
    definition of the polymer sequence. Without that datum, using the
    polymer in a complex context would be impossible, as the polymer
    chemistry definition will provide a huge amount of data required
    to operate the polymer efficiently. Because Ionizable inherits
    Ponderable, the polymer has a mono mass and an average mass.
  
    The polymer also has modifications(left-end and right-end) to
    characterize it better.
  */
  class Polymer : public QObject, public Sequence, public Ionizable
  {
    Q_OBJECT
  
    private:
    //! Name
    QString m_name;
    
    //! Code.
    QString m_code;
  
    //! Name of the last user having last modified the polymer sequence.
    QString m_author;
  
    //! File name.
    QString m_filePath;
  
    //! Date and time of the last modification.
    QDateTime m_dateTime;

    //! Left end modification.
    Modif m_leftEndModif;

    //! Right end modification.
    Modif m_rightEndModif;

    //! The list of CrossLink instances.
    CrossLinkList m_crossLinkList;
   

  public:
    Polymer(const PolChemDef *, const QString & = QString("NOT_SET"), 
	     const QString & = QString("NOT_SET"),
	     const QString & = QString("NOT SET"));

    virtual ~Polymer();
  
    void setName(const QString &);
    QString name() const;
  
    void setCode(const QString &);
    QString code() const;
  
    void setAuthor(const QString &);
    QString author() const;
  
    void setFilePath(const QString &);
    QString filePath() const;

    void setDateTime(const QString &);
    QString dateTime() const;

    bool setLeftEndModif(const QString & = QString());
    bool setLeftEndModif(const Modif &);
    const Modif &leftEndModif() const;
  
    bool setRightEndModif(const QString & = QString());
    bool setRightEndModif(const Modif &);
    const Modif &rightEndModif() const;

    const CrossLinkList &crossLinkList() const;
    CrossLinkList *crossLinkListPtr();
    bool crossLinkedMonomerIndexList(int, int, QList<int> *, int *);
    bool crossLinkList(int, int, QList<CrossLink *> *, int *);
    
    virtual bool prepareMonomerRemoval(Monomer *);
    virtual bool removeMonomerAt(int);
  
  
    // MASS CALCULATION FUNCTIONS
    /////////////////////////////

    bool accountMasses(const CalcOptions &);
    static bool accountMasses(Polymer *,
			       const CalcOptions &,
			       double *, double *);
  
    bool calculateMasses(const CalcOptions &, bool = true);
    static bool calculateMasses(Polymer *, const CalcOptions &,
				 double *, double *, bool = true);
    
    bool accountCappingMasses(int, int = 1);
    static bool accountCappingMasses(Polymer *, int,
				      double *, double *, int = 1);

    bool accountEndModifMasses(int);
    static bool accountEndModifMasses(Polymer *, int,
				       double *, double *);
    static bool accountEndModifMasses(Polymer *, int,
				       Ponderable *);

    bool crossLink(CrossLink *);
    bool uncrossLink(CrossLink *);
    
    /////////////////////////////
    // MASS CALCULATION FUNCTIONS

    // ELEMENTAL CALCULATION FUNCTION
    /////////////////////////////////
    
    QString elementalComposition(const IonizeRule &,
                                 const CoordinateList &,
                                 const CalcOptions &);
    
    /////////////////////////////////
    // ELEMENTAL CALCULATION FUNCTION
    
    bool renderXmlCodesElement(const QDomElement &element);

    static QString xmlPolymerFileGetPolChemDefName(const QString &filePath);
  
    bool renderXmlPolymerFile(QString = QString(""));
    bool renderXmlPolymerModifElement(const QDomElement &, int);
    bool renderXmlPolymerModifElement(const QDomElement &);
    bool renderXmlPolymerModifElementV3(const QDomElement &);
    bool renderXmlPolymerModifElementV4(const QDomElement &);
    bool renderXmlCrossLinksElement(const QDomElement &, int);
  
    QString *formatXmlDtd();
    QString *formatXmlPolSeqElement(int, const QString & = QString("  "));
    QString *formatXmlCrossLinksElement(int, const QString & = QString("  "));

    bool writeXmlFile();

    bool validate();
  
    void debugPutStdErr();

  signals:
    void polymerDestroyedSignal(Polymer *);
    void crossLinkChangedSignal(Polymer *);
    void crossLinksPartiallyEncompassedSignal(int) const;
  };

} // namespace massXpert


#endif // POLYMER_HPP
