/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2018 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the msXpertSuite project.
 *
 * The msXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


#ifndef POLYMER_HPP
#define POLYMER_HPP


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


/////////////////////// Local includes
#include "Sequence.hpp"
#include "Ionizable.hpp"
#include "PolChemDef.hpp"
#include "Modif.hpp"
#include "CalcOptions.hpp"
#include "CrossLinkList.hpp"


namespace msxps
{

	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 hasModifiedMonomer(int leftIndex = -1, int rightIndex = -1) const;

  bool setLeftEndModif(const QString & = QString());
  bool setLeftEndModif(const Modif &);
  const Modif &leftEndModif() const;
  bool isLeftEndModified() const;

  bool setRightEndModif(const QString & = QString());
  bool setRightEndModif(const Modif &);
  const Modif &rightEndModif() const;
  bool isRightEndModified() const;


  const CrossLinkList &crossLinkList() const;
  CrossLinkList *crossLinkListPtr();
  bool crossLinkedMonomerIndexList(int, int, QList<int> *, int *);
  bool crossLinkList(int, int, QList<CrossLink *> *, int *);


#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
  virtual bool prepareMonomerRemoval(Monomer *);
#pragma clang diagnostic pop

  virtual bool removeMonomerAt(int);

  QByteArray md5Sum(int hashAccountData) const;


  // MASS CALCULATION FUNCTIONS
  /////////////////////////////

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
  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);
#pragma clang diagnostic pop


  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

} // namespace msxps


#endif // POLYMER_HPP
