/* 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
 */


#pragma once

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


/////////////////////// Local includes
#include "exportimportconfig.h"
#include "Formula.hpp"
#include "IsotopicData.hpp"
#include "Modif.hpp"
#include "CrossLinker.hpp"
#include "CleaveSpec.hpp"
#include "FragSpec.hpp"
#include "IonizeRule.hpp"
#include "Polymer.hpp"
#include "MonomerSpec.hpp"
#include "ModifSpec.hpp"
#include "CrossLinkerSpec.hpp"
#include "PolChemDefSpec.hpp"


namespace MsXpS
{

namespace libXpertMass
{

extern const int POL_CHEM_DEF_FILE_FORMAT_VERSION;

class PolChemDef;
typedef std::shared_ptr<PolChemDef> PolChemDefSPtr;
typedef std::shared_ptr<const PolChemDef> PolChemDefCstSPtr;


//! The PolChemDef class provides a polymer chemistry definition.
/*! A polymer chemistry definition allows one to characterize in a
  fine manner the chemistry of a polymer. That means that it should
  contain:

  -  a list of atoms;

  - a list of monomers;

  - a list of modifications;

  - a list of cross-linkers;

  - a list of cleavage specifications;

  - a list of fragmentation specifications;

  and a number of chemical data, like the left and right cap formulas,
  the code length(that is the maximum number of characters that might
  be used to construct a monomer code).

  Because monomers have to be graphically rendered at some point, in
  the form of monomer vignettes in the sequence editor, the polymer
  chemistry definition also contains:

  - a list of monomer specifications, which tell the sequence editor
  what file is to be used to render any monomer in the polymer
  chemistry definition;

  - a list of modification specifications, which tell the sequence
  editor what file is to be used to render any chemical
  modification;
*/
class DECLSPEC PolChemDef
{

  public:
  PolChemDef();
  PolChemDef(const PolChemDefSpec &);

  virtual ~PolChemDef();

  void setVersion(const QString &);
  QString version() const;

  void setName(const QString &);
  QString name() const;

  void setXmlDataFilePath(const QString &file_path);
  QString getXmlDataFilePath() const;
  QString getXmlDataDirPath() const;

  void setIsotopicDataFilePath(const QString &file_path);
  QString getIsotopicDataFilePath() const;
  QString deduceIsotopicDataFilePath() const;

  void setLeftCap(const Formula &);
  const Formula &leftCap() const;

  void setRightCap(const Formula &);
  const Formula &rightCap() const;

  void setCodeLength(int);
  int codeLength() const;

  bool calculateDelimitedCodes();
  const QString &delimitedCodes();

  void setIonizeRule(const IonizeRule &);
  const IonizeRule &ionizeRule() const;
  IonizeRule *ionizeRulePtr();

  void setIsotopicDataSPtr(IsotopicDataSPtr isotopic_data_sp);
  IsotopicDataCstSPtr getIsotopicDataCstSPtr() const;
  IsotopicDataSPtr getIsotopicDataSPtr();

  const QList<Monomer *> &monomerList() const;
  QList<Monomer *> *monomerListPtr();

  const QList<Modif *> &modifList() const;
  QList<Modif *> *modifListPtr();

  const QList<CrossLinker *> &crossLinkerList() const;
  QList<CrossLinker *> *crossLinkerListPtr();

  const QList<CleaveSpec *> &cleaveSpecList() const;
  QList<CleaveSpec *> *cleaveSpecListPtr();

  const QList<FragSpec *> &fragSpecList() const;
  QList<FragSpec *> *fragSpecListPtr();

  QList<MonomerSpec *> &monomerSpecList() const;
  QList<MonomerSpec *> *monomerSpecListPtr();

  QList<ModifSpec *> &modifSpecList() const;
  QList<ModifSpec *> *modifSpecListPtr();

  QList<CrossLinkerSpec *> &crossLinkerSpecList() const;
  QList<CrossLinkerSpec *> *crossLinkerSpecListPtr();

  bool referenceModifByName(const QString &, Modif * = 0) const;
  bool referenceCrossLinkerByName(const QString &, CrossLinker * = 0) const;

  static std::size_t loadIsotopicData(PolChemDefSPtr pol_chem_def_sp,
                                      const QString &file_path = QString());

  static std::size_t writeIsotopicData(PolChemDefSPtr pol_chem_def_sp,
                                       const QString &file_path = QString());

  static bool renderXmlPolChemDefFile(PolChemDefSPtr pol_chem_def_sp);

  QString *formatXmlDtd();

  bool writeXmlFile();

  QStringList *differenceBetweenMonomers(double, MassType);

  protected:
  //! Name.
  /*! Identifies the polymer definition, like "protein" or "dna", for
    example.
  */
  QString m_name;

  //! File path.
  /*! Fully qualifies the file which contains the polymer chemistry definition.
   */
  QString m_xmlDataFilePath;

  QString m_isotopicDataFilePath;

  //! Left cap formula.
  /*! Describes how the polymer should be capped on its left end.
   */
  Formula m_leftCap;

  //! Right cap formula.
  /*! Describes how the polymer should be capped on its right end.
   */
  Formula m_rightCap;

  //! Code length.
  /*! Maximum number of characters allowed to construct a monomer
    code.
  */
  int m_codeLength;

  //! Delimited codes string.
  /*! String made with each code of each monomer separated using '@',
    like "@Ala@Tyr@Phe@".
  */
  QString m_delimitedCodes;

  //! Ionization rule.
  /*! The ionization rule indicates how the polymer sequence needs be
    ionized by default.
  */
  IonizeRule m_ionizeRule;

  //! Shared pointer to IsotopicData
  // We will access all the chemical elements data in this class instance.
  IsotopicDataSPtr msp_isotopicData = nullptr;

  //! List of monomers.
  QList<Monomer *> m_monomerList;

  //! List of modifications.
  QList<Modif *> m_modifList;

  //! List of cross-linkers.
  QList<CrossLinker *> m_crossLinkerList;

  //! List of cleavage specifications.
  QList<CleaveSpec *> m_cleaveSpecList;

  //! List of fragmentation specifications.
  QList<FragSpec *> m_fragSpecList;

  //! List of monomer specifications.
  /*! Each monomer in the polymer chemistry definition has an item in
    this list indicating where the graphics file is to be found for
    graphical rendering.
  */
  mutable QList<MonomerSpec *> m_monomerSpecList;

  //! List of modification specifications.
  /*! Each modification in the polymer chemistry definition has an
    item in this list indicating where the graphics file is to be
    found for graphical rendering and the graphical mechanism to be
    used for rendering the modification graphically.
  */
  mutable QList<ModifSpec *> m_modifSpecList;

  //! List of cross-link specifications.
  /*! Each cross-link in the polymer chemistry definition has an item
    in this list indicating where the graphics file is to be found for
    graphical rendering.
  */
  mutable QList<CrossLinkerSpec *> m_crossLinkerSpecList;

  QList<PolChemDef *> *mp_repositoryList;
};

} // namespace libXpertMass

} // namespace MsXpS


Q_DECLARE_METATYPE(MsXpS::libXpertMass::PolChemDefSPtr);
extern int polChemDefSPtrMetaTypeId;

Q_DECLARE_METATYPE(MsXpS::libXpertMass::PolChemDefCstSPtr);
extern int polChemDefCstSPtrMetaTypeId;
