// GPL 3+
// Filippo Rusconi

#pragma once

/////////////////////// StdLib includes
#include <map>
#include <limits>


/////////////////////// Qt includes


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


/////////////////////// Local includes
#include "../massspectrum/qualifiedmassspectrum.h"
#include "pappsomspp/core/precision.h"
#include "msrundatasettreevisitor.h"
#include "pappsomspp/export-import-config.h"


namespace pappso
{

class MsRunDataSetTreeNode;

typedef std::shared_ptr<MsRunDataSetTreeNode> MsRunDataSetTreeNodeSPtr;
typedef std::shared_ptr<const MsRunDataSetTreeNode> MsRunDataSetTreeNodeCstSPtr;

class PMSPP_LIB_DECL MsRunDataSetTreeNode
{
  friend class MsRunDataSetTree;

  public:
  MsRunDataSetTreeNode();
  MsRunDataSetTreeNode(const MsRunDataSetTreeNode &other);

  MsRunDataSetTreeNode(QualifiedMassSpectrumCstSPtr mass_spectrum_csp,
                       MsRunDataSetTreeNode *parent_p = nullptr);

  virtual ~MsRunDataSetTreeNode();

  MsRunDataSetTreeNode &operator=(const MsRunDataSetTreeNode &other);

  void setQualifiedMassSpectrum(
    QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp);
  QualifiedMassSpectrumCstSPtr getQualifiedMassSpectrum() const;

  void setParent(MsRunDataSetTreeNode *parent);
  MsRunDataSetTreeNode *getParent() const;
  bool hasParent() const;

  void size(std::size_t &cumulative_node_count) const;

  MsRunDataSetTreeNode *findNode(std::size_t spectrum_index);
  MsRunDataSetTreeNode *
  findNode(QualifiedMassSpectrumCstSPtr mass_spectrum_csp);

  void flattenedView(std::vector<MsRunDataSetTreeNode *> &nodes,
                     bool with_descendants = false);
  void flattenedViewChildrenOnly(std::vector<MsRunDataSetTreeNode *> &nodes,
                                 bool with_descendants = false);

  void flattenedViewMsLevelNodes(std::size_t ms_level,
                                 std::size_t depth,
                                 std::vector<MsRunDataSetTreeNode *> &nodes,
                                 bool with_descendants = false);

  std::vector<MsRunDataSetTreeNode *>
  productNodesByPrecursorMz(pappso_double precursor_mz,
                            PrecisionPtr precision_ptr,
                            std::vector<MsRunDataSetTreeNode *> &nodes);


  std::vector<MsRunDataSetTreeNode *>
  precursorIonNodesByPrecursorMz(pappso_double precursor_mz,
                                 PrecisionPtr precision_ptr,
                                 std::vector<MsRunDataSetTreeNode *> &nodes);


  void accept(MsRunDataSetTreeNodeVisitorInterface &visitor);

  // Utility functions.
  std::size_t depth(std::size_t depth) const;

  QString toString(bool with_data = false) const;

  private:
  QualifiedMassSpectrumCstSPtr mcsp_massSpectrum = nullptr;

  MsRunDataSetTreeNode *mp_parent = nullptr;

  std::vector<MsRunDataSetTreeNode *> m_children;
};

} // namespace pappso
