/**
 * \file pappsomspp/amino_acid/aamodification.h
 * \date 7/3/2015
 * \author Olivier Langella
 * \brief amino acid modification model
 */

/*******************************************************************************
 * Copyright (c) 2015 Olivier Langella <Olivier.Langella@moulon.inra.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ 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.
 *
 *     PAPPSOms++ 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 PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/


#pragma once

#include <QDebug>
#include <QString>
#include <QMutex>
#include <memory>
#include <map>
#include "../types.h"
#include "atomnumberinterface.h"
#include "../obo/obopsimod.h"

namespace pappso
{


class Peptide;
typedef std::shared_ptr<const Peptide> PeptideSp;

class AaModification;
typedef std::unique_ptr<const AaModification> AaModificationUp;
typedef const AaModification *AaModificationP;

class Aa;

class PMSPP_LIB_DECL AaModification : public AtomNumberInterface
{
  private:
  pappso_double m_mass;
  QString m_origin;
  std::map<AtomIsotopeSurvey, int> m_atomCount;
  std::map<Isotope, int> m_mapIsotope;

  AaModification(const QString &accession, pappso_double mass);
  static AaModificationP createInstance(const QString &saccession);
  static AaModificationP createInstance(const OboPsiModTerm &term);
  static AaModificationP createInstanceMutation(const Aa &aa_from,
                                                const Aa &aa_to);
  void calculateMassFromChemicalComponents();

  using MapAccessionModifications = std::map<QString, AaModificationP>;
  static MapAccessionModifications m_mapAccessionModifications;

  static QMutex m_mutex;

  protected:
  const QString m_accession;
  QString m_name;
  void setDiffFormula(const QString &diff_formula);
  /** @brief set list of amino acid on which this modification takes place
   *
   * @arg origin string of the form "S T" for Serine or Threonine, "X" for any
   * amino acid (see OBO PSI format)
   * */
  void setXrefOrigin(const QString &origin);


  public:
  AaModification(AaModification &&toCopy); // move constructor

  static AaModificationP getInstance(const QString &accession);
  static AaModificationP getInstance(const OboPsiModTerm &oboterm);

  /** @brief get a fake modification coding a mutation from an amino acid to an
   * other
   * @param mut_from orginal amino acid
   * @param mut_to targeted amino acid
   */
  static AaModificationP getInstanceMutation(const QChar &mut_from,
                                             const QChar &mut_to);
  static AaModificationP getInstanceXtandemMod(const QString &type,
                                               pappso_double mass,
                                               const PeptideSp &peptide_sp,
                                               unsigned int position);
  static AaModificationP
  getInstanceCustomizedMod(pappso_double modificationMass);

  const QString &getAccession() const;
  const QString &getName() const;

  ~AaModification();

  pappso_double getMass() const;
  int getNumberOfAtom(AtomIsotopeSurvey atom) const override final;
  int getNumberOfIsotope(Isotope isotope) const override final;
  bool isInternal() const;
};

} // namespace pappso
