/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2026 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
 */


/////////////////////// StdLib includes
#include <cmath>


/////////////////////// Qt includes
#include <QDebug>
#include <QThread>


/////////////////////// pappsomspp includes
#include <pappsomspp/core/processing/filters/filterresample.h>
#include <pappsomspp/core/processing/filters/filterpass.h>


/////////////////////// Local includes
#include "MsRunStatisticsTreeNodeVisitor.hpp"

namespace MsXpS
{
namespace MineXpert
{


MsRunStatisticsTreeNodeVisitor::MsRunStatisticsTreeNodeVisitor(
  MsRunDataSetCstSPtr ms_run_data_set_csp,
  const ProcessingFlow &processing_flow,
  const MsRunDataSetStats &ms_run_data_set_stats,
  QObject *parent)
  : BaseMsRunDataSetTreeNodeVisitor(
      ms_run_data_set_csp, processing_flow, parent),
    m_msRunDataSetStats(ms_run_data_set_stats)
{
}

MsRunStatisticsTreeNodeVisitor::~MsRunStatisticsTreeNodeVisitor()
{
  // qDebug();
}

BaseMsRunDataSetTreeNodeVisitor *
MsRunStatisticsTreeNodeVisitor::clone(QObject *parent) const
{
  MsRunStatisticsTreeNodeVisitor *copy = new MsRunStatisticsTreeNodeVisitor(
    mcsp_msRunDataSet, *mp_processingFlow, m_msRunDataSetStats, parent);

  return copy;
}

const MsRunDataSetStats &
MsRunStatisticsTreeNodeVisitor::getMsRunDataSetStats() const
{
  return m_msRunDataSetStats;
}

bool
MsRunStatisticsTreeNodeVisitor::visit(const pappso::MsRunDataSetTreeNode &node)
{

  // Each time we visit a node, we check that it matches all the requirements in
  // the ProcessingFlow. Then, if that is the case, we aggregrate its statistics
  // to the MsRunDataSets member datum.

  // qDebug() << "Visiting node:" << node.toString() << "from thread:" <<
  // QThread::currentThread(); qDebug() << "Visiting node from thread:" <<
  // QThread::currentThread();

  if(!m_isProgressFeedbackSilenced)
    {
      // Whatever the status of this node (to be or not processed) let the user
      // know that we have gone through one more.

      // The "%c" format refers to the current value in the task monitor widget
      // that will craft the new text according to the current value after
      // having incremented it in the call below. This is necessary because this
      // visitor might be in a thread and the  we need to account for all the
      // thread when giving feedback to the user.

      emit taskSetStatusMessageAndIncrementCurrentValueSignal(
        "Processed %c nodes", 1);
    }


  // qDebug().noquote() << "Visiting node:" << &node << "text format:" <<
  // node.toString()
  //<< "with quaified mass spectrum:"
  //<< node.getQualifiedMassSpectrum()->toString();

  pappso::QualifiedMassSpectrumCstSPtr qualified_mass_spectrum_csp =
    checkQualifiedMassSpectrum(node);

  if(qualified_mass_spectrum_csp == nullptr)
    {
      qFatal() << "Failed to read the mass spectral data from the file.";
    }

  // qDebug().noquote() << "Visiting qualified mass spectrum:"
  //<< qualified_mass_spectrum_csp->toString();

  // We do not check the MS level because we want all the mass spectra to be
  // accounted for because we need to know the smallest value of all the m/z
  // values in the whole data set, irrespective of MS level.

  // Make easy check about RT and DT.

  if(!checkRtRange(qualified_mass_spectrum_csp))
    {
      // qDebug() << "checkRtRange failed check.";

      return false;
    }
  if(!checkDtRange(qualified_mass_spectrum_csp))
    {
      // qDebug() << "checkDtRange failed check.";

      return false;
    }

  // qDebug() << "The current qualified mass spectrum has size:"
  //<< qualified_mass_spectrum_csp->size();

  pappso::MassSpectrum filtered_mass_spectrum;

  if(!std::isnan(m_mzRange.first) && !std::isnan(m_mzRange.second))
    {
      // Before analyzing statistically the mass spectrum, we need to check
      // that we work on the proper mz range asked by the caller. Here we need
      // to filter the mass spectrum to only keep the m/z range specified.

      pappso::FilterResampleKeepXRange filter;

      // The filter changes the Trace (or MassSpectrum) *in place*, so we need
      // to first create a copy.
      filtered_mass_spectrum.initialize(
        *(qualified_mass_spectrum_csp->getMassSpectrumSPtr()));

      filtered_mass_spectrum = filter.filter(filtered_mass_spectrum);
    }
  else
    {
      // We do not want to bother with y=0 data points !
      pappso::FilterHighPass filter(0.0);

      // The filter changes the Trace (or MassSpectrum) *in place*, so we need
      // to first create a copy.
      filtered_mass_spectrum.initialize(
        *(qualified_mass_spectrum_csp->getMassSpectrumSPtr()));

      filtered_mass_spectrum = filter.filter(filtered_mass_spectrum);
    }

  // At this point, either we used filters, and filtered_mass_spectrum.size() is
  // non-0, or we must use the origianl mass spectrum.

  if(filtered_mass_spectrum.size())
    m_msRunDataSetStats.incrementStatistics(filtered_mass_spectrum);
  else
    m_msRunDataSetStats.incrementStatistics(
      *(qualified_mass_spectrum_csp->getMassSpectrumSPtr()));

  // qDebug() << "After statistics incrementation, m_maxMz:" <<
  // m_msRunDataSetStats.m_maxMz;

  // qDebug().noquote() << "statistics:" << m_msRunDataSetStats.toString();

  return true;
}


} // namespace MineXpert

} // namespace MsXpS
