/* BEGIN software license
 *
 * MsXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright (C) 2009--2020 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


/////////////////////// Stdlib includes
#include <limits>
#include <vector>
#include <memory>


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


/////////////////////// pappsomspp includes


/////////////////////// Local includes
#include "MsXpS/export-import-config.h"

#include "MsXpS/libXpertMassCore/jsclassregistrar.h"
#include "MsXpS/libXpertMassCore/Isotope.hpp"
#include "MsXpS/libXpertMassCore/globals.hpp"

namespace MsXpS
{
namespace libXpertMassCore
{

using IsotopeListCstIterator = QList<QSharedPointer<Isotope>>::const_iterator;
using IsotopeListIterator    = QList<QSharedPointer<Isotope>>::iterator;
using IsotopeListCstIteratorPair =
  std::pair<IsotopeListCstIterator, IsotopeListCstIterator>;

/*  BEGIN CLASS JS REFERENCE
 *  namespace: MsXpS::libXpertMassCore
 *  class name: IsotopicData
 */

class DECLSPEC IsotopicData: public QObject
{
  Q_OBJECT

  friend class IsotopicDataBaseHandler;
  friend class IsotopicDataLibraryHandler;
  friend class IsotopicDataUserConfigHandler;
  friend class IsotopicDataManualConfigHandler;

  Q_PROPERTY(std::size_t size READ size)

  public:
  Q_INVOKABLE IsotopicData(QObject *parent = nullptr);
  // Pseudo copy constructor
  Q_INVOKABLE IsotopicData(const IsotopicData &other,
                           QObject *parent = nullptr);

  virtual ~IsotopicData();

  Q_INVOKABLE void setFilePath(const QString &file_path);
  Q_INVOKABLE QString getFilePath() const;

  Q_INVOKABLE void appendNewIsotope(IsotopeQSPtr isotope_qsp,
                                    bool update_maps = true);
  Q_INVOKABLE bool insertNewIsotope(IsotopeQSPtr isotope_qsp,
                                    qsizetype index,
                                    bool update_maps = true);

  Q_INVOKABLE void appendNewIsotopes(const QList<IsotopeQSPtr> &isotopes,
                                     bool update_maps = true);

  IsotopeListCstIterator eraseIsotopes(qsizetype begin_index,
                                       qsizetype end_index,
                                       bool update_maps = true);


  /////////////////////////////////////////////////////////
  /// Function to be run each time something is loaded or anything is changed
  /// int the m_isotopes vector.

  Q_INVOKABLE bool updateMonoMassMap(const QString &symbol);
  Q_INVOKABLE std::size_t updateMonoMassMap();

  Q_INVOKABLE bool updateAvgMassMap(const QString &symbol);
  Q_INVOKABLE std::size_t updateAvgMassMap();

  Q_INVOKABLE double computeAvgMass(IsotopeListCstIteratorPair iter_pair,
                                    ErrorList *error_list_p) const;

  Q_INVOKABLE void updateMassMaps(const QString &symbol);
  Q_INVOKABLE std::size_t updateMassMaps();

  /////////////////////////////////////////////////////////
  /// All the functions needed to access the various bits from the m_isotopes
  /// vector of IsotopeQSPtr instances.

  // Get the monoisotopic mass of carbon.
  Q_INVOKABLE double getMonoMassBySymbol(const QString &symbol, bool &ok) const;
  Q_INVOKABLE double getMonoMass(IsotopeListCstIteratorPair iter_pair,
                                 ErrorList *error_list_p) const;

  Q_INVOKABLE double getAvgMassBySymbol(const QString &symbol, bool &ok) const;

  Q_INVOKABLE double
  getCumulatedProbabilitiesBySymbol(const QString &symbol,
                                    ErrorList *error_list_p) const;

  Q_INVOKABLE double getHighestProbability(const QString &symbol,
                                           ErrorList *error_list_p) const;

  Q_INVOKABLE IsotopeListCstIterator getHighestProbabilityIterator(
    const QString &symbol, ErrorList *error_list_p) const;

  Q_INVOKABLE double
  getCumulatedProbabilities(IsotopeListCstIteratorPair iter_pair,
                            ErrorList *error_list_p) const;

  IsotopeListCstIteratorPair getIsotopesBySymbol(const QString &symbol) const;

  Q_INVOKABLE qsizetype getIsotopeCountBySymbol(const QString &symbol) const;

  IsotopeListCstIteratorPair getIsotopesByName(const QString &name) const;

  std::vector<QString> getUniqueSymbolsInOriginalOrder() const;

  Q_INVOKABLE bool containsSymbol(const QString &symbol, int &count) const;
  Q_INVOKABLE bool containsName(const QString &name, int &count) const;

  Q_INVOKABLE QString isotopesAsStringBySymbol(const QString &symbol) const;

  Q_INVOKABLE bool isMonoMassIsotope(IsotopeCstQSPtr isotope_cqsp);

  const QList<QSharedPointer<Isotope>> &getIsotopes() const;

  IsotopicData &operator=(const IsotopicData &other);
  bool operator==(const IsotopicData &other) const;
  bool operator!=(const IsotopicData &other) const;

  // The number of isotopes in m_isotopes.
  qsizetype size() const;

  bool isValid();

  // The number of different symbols (that is, chemical elements) in the data
  qsizetype getUniqueSymbolsCount() const;

  bool validate(ErrorList *error_list_p) const;
  bool validateBySymbol(const QString &symbol, ErrorList *error_list_p) const;
  bool validateAllBySymbol(ErrorList *error_list_p) const;

  void replace(IsotopeQSPtr old_isotope_sp, IsotopeQSPtr new_isotope_sp);

  void clearSymbolMassMaps();

  void clear();

  static void registerJsConstructor(QJSEngine *engine);

  protected:
  QString m_filePath;
  // The container should never be sorted as we want to keep the order of the
  // isotopes in the way the vector has been populated, either by looking into
  // the IsoSpec library tables or by reading data from a user-configured file.

  // QList<IsotopeQSPtr> m_isotopes;
  QList<QSharedPointer<Isotope>> m_isotopes;

  // std::map<QString, double> m_symbolMonoMassMap;
  QMap<QString, double> m_symbolMonoMassMap;
  // std::map<QString, double> m_symbolAvgMassMap;
  QMap<QString, double> m_symbolAvgMassMap;

  mutable bool m_isValid = false;
};

typedef std::shared_ptr<IsotopicData> IsotopicDataSPtr;
typedef std::shared_ptr<const IsotopicData> IsotopicDataCstSPtr;

/*  END CLASS JS REFERENCE
 *  namespace: MsXpS::libXpertMassCore
 *  class name: IsotopicData
 */

} // namespace libXpertMassCore
MSXPS_REGISTER_JS_CLASS(MsXpS::libXpertMassCore, IsotopicData)
} // namespace MsXpS
