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


/////////////////////// StdLib includes


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


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


/////////////////////// Local includes
#include "MsRunDataSetStats.hpp"
#include "globals.hpp"

namespace MsXpS
{
namespace MineXpert
{


MsRunDataSetStats::MsRunDataSetStats()
{
}

MsRunDataSetStats::MsRunDataSetStats(const MsRunDataSetStats &other)
{
  m_spectrumCount = other.m_spectrumCount;

  m_smallestSpectrumSize = other.m_smallestSpectrumSize;
  m_greatestSpectrumSize = other.m_greatestSpectrumSize;
  m_spectrumSizeAvg      = other.m_spectrumSizeAvg;
  m_spectrumSizeStdDev   = other.m_spectrumSizeStdDev;

  // First m/z value found in *all* the spectra (that is the minimum m/z
  // value encountered in the whole spectral data set).
  m_minMz         = other.m_minMz;
  m_firstMzAvg    = other.m_firstMzAvg;
  m_firstMzStdDev = other.m_firstMzStdDev;

  // Last m/z value found in *all* the spectra (that is the maximum m/z
  // value encountered in the whole spectral data set).
  m_maxMz        = other.m_maxMz;
  m_lastMzAvg    = other.m_lastMzAvg;
  m_lastMzStdDev = other.m_lastMzStdDev;

  m_smallestMzShift = other.m_smallestMzShift;
  m_greatestMzShift = other.m_greatestMzShift;
  m_mzShiftAvg      = other.m_mzShiftAvg;
  m_mzShiftStdDev   = other.m_mzShiftStdDev;

  // This value is set along with the MASS_TOLERANCE_MZ value!
  // Only account for values that are > 0.
  m_nonZeroSmallestStep = other.m_nonZeroSmallestStep;
  m_smallestStep        = other.m_smallestStep;
  m_smallestStepMedian  = other.m_smallestStepMedian;
  m_smallestStepAvg     = other.m_smallestStepAvg;
  m_smallestStepStdDev  = other.m_smallestStepStdDev;

  m_greatestStep       = other.m_greatestStep;
  m_greatestStepAvg    = other.m_greatestStepAvg;
  m_greatestStepStdDev = other.m_greatestStepStdDev;

  // Copy all the vectors.
  m_spectrumSizes.reserve(other.m_spectrumSizes.size());
  m_spectrumSizes.insert(m_spectrumSizes.end(),
                         other.m_spectrumSizes.begin(),
                         other.m_spectrumSizes.end());

  m_firstMzs.reserve(other.m_firstMzs.size());
  m_firstMzs.insert(
    m_firstMzs.end(), other.m_firstMzs.begin(), other.m_firstMzs.end());

  m_lastMzs.reserve(other.m_lastMzs.size());
  m_lastMzs.insert(
    m_lastMzs.end(), other.m_lastMzs.begin(), other.m_lastMzs.end());

  m_mzShifts.reserve(other.m_mzShifts.size());
  m_mzShifts.insert(
    m_mzShifts.end(), other.m_mzShifts.begin(), other.m_mzShifts.end());

  m_smallestSteps.reserve(other.m_smallestSteps.size());
  m_smallestSteps.insert(m_smallestSteps.end(),
                         other.m_smallestSteps.begin(),
                         other.m_smallestSteps.end());

  m_greatestSteps.reserve(other.m_greatestSteps.size());
  m_greatestSteps.insert(m_greatestSteps.end(),
                         other.m_greatestSteps.begin(),
                         other.m_greatestSteps.end());

  m_avgSteps.reserve(other.m_avgSteps.size());
  m_avgSteps.insert(
    m_avgSteps.end(), other.m_avgSteps.begin(), other.m_avgSteps.end());

  m_stdDevSteps.reserve(other.m_stdDevSteps.size());
  m_stdDevSteps.insert(m_stdDevSteps.end(),
                       other.m_stdDevSteps.begin(),
                       other.m_stdDevSteps.end());
}

MsRunDataSetStats &
MsRunDataSetStats::operator=(const MsRunDataSetStats &other)
{
  if(this == &other)
    return *this;

  reset();

  m_spectrumCount = other.m_spectrumCount;

  m_smallestSpectrumSize = other.m_smallestSpectrumSize;
  m_greatestSpectrumSize = other.m_greatestSpectrumSize;
  m_spectrumSizeAvg      = other.m_spectrumSizeAvg;
  m_spectrumSizeStdDev   = other.m_spectrumSizeStdDev;

  // First m/z value found in *all* the spectra (that is the minimum m/z
  // value encountered in the whole spectral data set).
  m_minMz         = other.m_minMz;
  m_firstMzAvg    = other.m_firstMzAvg;
  m_firstMzStdDev = other.m_firstMzStdDev;

  // Last m/z value found in *all* the spectra (that is the maximum m/z
  // value encountered in the whole spectral data set).
  m_maxMz        = other.m_maxMz;
  m_lastMzAvg    = other.m_lastMzAvg;
  m_lastMzStdDev = other.m_lastMzStdDev;

  m_smallestMzShift = other.m_smallestMzShift;
  m_greatestMzShift = other.m_greatestMzShift;
  m_mzShiftAvg      = other.m_mzShiftAvg;
  m_mzShiftStdDev   = other.m_mzShiftStdDev;

  // This value is set along with the MASS_TOLERANCE_MZ value!
  m_nonZeroSmallestStep = other.m_nonZeroSmallestStep;
  m_smallestStep        = other.m_smallestStep;
  m_smallestStepMedian  = other.m_smallestStepMedian;
  m_smallestStepAvg     = other.m_smallestStepAvg;
  m_smallestStepStdDev  = other.m_smallestStepStdDev;

  m_greatestStep       = other.m_greatestStep;
  m_greatestStepAvg    = other.m_greatestStepAvg;
  m_greatestStepStdDev = other.m_greatestStepStdDev;

  // Copy all the vectors.
  m_spectrumSizes.clear();
  m_spectrumSizes.reserve(other.m_spectrumSizes.size());
  m_spectrumSizes.insert(m_spectrumSizes.end(),
                         other.m_spectrumSizes.begin(),
                         other.m_spectrumSizes.end());

  m_firstMzs.clear();
  m_firstMzs.reserve(other.m_firstMzs.size());
  m_firstMzs.insert(
    m_firstMzs.end(), other.m_firstMzs.begin(), other.m_firstMzs.end());

  m_lastMzs.clear();
  m_lastMzs.reserve(other.m_lastMzs.size());
  m_lastMzs.insert(
    m_lastMzs.end(), other.m_lastMzs.begin(), other.m_lastMzs.end());

  m_mzShifts.clear();
  m_mzShifts.reserve(other.m_mzShifts.size());
  m_mzShifts.insert(
    m_mzShifts.end(), other.m_mzShifts.begin(), other.m_mzShifts.end());

  m_smallestSteps.clear();
  m_smallestSteps.reserve(other.m_smallestSteps.size());
  m_smallestSteps.insert(m_smallestSteps.end(),
                         other.m_smallestSteps.begin(),
                         other.m_smallestSteps.end());

  m_greatestSteps.clear();
  m_greatestSteps.reserve(other.m_greatestSteps.size());
  m_greatestSteps.insert(m_greatestSteps.end(),
                         other.m_greatestSteps.begin(),
                         other.m_greatestSteps.end());

  m_avgSteps.clear();
  m_avgSteps.reserve(other.m_avgSteps.size());
  m_avgSteps.insert(
    m_avgSteps.end(), other.m_avgSteps.begin(), other.m_avgSteps.end());

  m_stdDevSteps.clear();
  m_stdDevSteps.reserve(other.m_stdDevSteps.size());
  m_stdDevSteps.insert(m_stdDevSteps.end(),
                       other.m_stdDevSteps.begin(),
                       other.m_stdDevSteps.end());

  return *this;
}

MsRunDataSetStats::~MsRunDataSetStats()
{
}

void
MsRunDataSetStats::reset()
{
  m_spectrumCount = 0;

  m_smallestSpectrumSize = std::numeric_limits<double>::max();
  m_greatestSpectrumSize = 0;
  m_spectrumSizeAvg      = 0;
  m_spectrumSizeStdDev   = 0;

  // First m/z value found in *all* the spectra (that is the minimum m/z
  // value encountered in the whole spectral data set).
  m_minMz         = std::numeric_limits<double>::max();
  m_firstMzAvg    = 0;
  m_firstMzStdDev = 0;

  // Last m/z value found in *all* the spectra (that is the maximum m/z
  // value encountered in the whole spectral data set).
  m_maxMz        = 0;
  m_lastMzAvg    = 0;
  m_lastMzStdDev = 0;

  m_smallestMzShift = std::numeric_limits<double>::max();
  m_greatestMzShift = 0;
  m_mzShiftAvg      = 0;
  m_mzShiftStdDev   = 0;

  m_nonZeroSmallestStep = std::numeric_limits<double>::max();
  m_smallestStep        = std::numeric_limits<double>::max();
  m_smallestStepMedian  = 0;
  m_smallestStepAvg     = 0;
  m_smallestStepStdDev  = 0;

  m_greatestStep       = 0;
  m_greatestStepAvg    = 0;
  m_greatestStepStdDev = 0;

  // Now clear all the vectors.
  m_spectrumSizes.clear();

  m_firstMzs.clear();
  m_lastMzs.clear();

  m_mzShifts.clear();

  m_smallestSteps.clear();
  m_greatestSteps.clear();
  m_avgSteps.clear();
  m_stdDevSteps.clear();
}

//! Fill-in \p bins with all the m/z intervals in \p mass_spectrum
/*!

  A bin is a m/z interval separating two consecutive m/z values in a mass
  spectrum. By definition, a mass spectrum that has n DataPoint instances has
  (n-1) intervals. A mass spectrum with less than two DataPoint instances is
  by
  definition not binnable.

  This function postulates that the data in the mass spectrum are sorted in
  key increasing order (that is, m/z increasing values). If not, the program
  crashes.

  The DataPoint instances in \p mass_spectrum are iterated over and for each
  previous \e vs current m/z value of two contiguous DataPoint instances, the
  (current - previous) m/z difference is computed and appended to \p
  binvector.

  \return the number of bins.

*/
int
MsRunDataSetStats::spectrumBins(const pappso::MassSpectrum &mass_spectrum,
                                std::vector<double> &bins)
{
  // qDebug();

  bins.clear();

  // We need at least two data points in the spectrum to compute the step
  // between the second and the first.

  if(mass_spectrum.size() < 2)
    {
      return 0;
    }

  double prevMz = mass_spectrum.front().x;

  using ConstIter = std::vector<pappso::DataPoint>::const_iterator;
  ConstIter it    = mass_spectrum.begin();

  ++it;

  while(it != mass_spectrum.end())
    {
      double curMz = it->x;

      double step = curMz - prevMz;

      // Sanity check:
      // Spectra are ascending-ordered for the mz value. If not, that's fatal.
      if(step > 0)
        bins.push_back(step);

      // QString msg = QString("Append step: %1 from computation %2 - %3 with
      // result: %4")
      //.arg(step, 0, 'f', 10)
      //.arg(curMz, 0, 'f', 10)
      //.arg(prevMz, 0, 'f', 10)
      //.arg(curMz - prevMz, 0, 'f', 10);
      // qDebug() << msg;

      prevMz = curMz;

      ++it;
    }

  return bins.size();
}

void
MsRunDataSetStats::incrementStatistics(
  const pappso::MassSpectrum &mass_spectrum)
{

  std::size_t mass_spectrum_size = mass_spectrum.size();

  if(!mass_spectrum_size)
    {
      // qDebug() << "The mass spectrum is empty, nothing to do, returning.";
      return;
    }
  // else
  //{
  // qDebug() << "The mass spectrum has size:" << mass_spectrum_size;
  //}

  // We can actually handle this spectrum, so increase the counter.
  ++m_spectrumCount;

  m_spectrumSizes.push_back(mass_spectrum_size);

  // The smallest spectrum size
  if(mass_spectrum_size < m_smallestSpectrumSize)
    m_smallestSpectrumSize = mass_spectrum_size;

  // The greatest spectrum size
  if(mass_spectrum_size > m_greatestSpectrumSize)
    m_greatestSpectrumSize = mass_spectrum_size;

  // The first m/z value of the mz vector of the spectrum
  double first_mz = mass_spectrum.front().x;

  // qDebug() << "The first_mz is:" << first_mz;

  m_firstMzs.push_back(first_mz);

  // The minimum m/z value
  if(first_mz < m_minMz)
    m_minMz = first_mz;

  double temp_double;

  // The smallest m/z shift, that is the difference between the various first
  // m/z values in a collection of mass spectra (different m/z vector root
  // problem). The first m/z value ever (the first m/z value of the first
  // spectrum in the series is the reference point).

  temp_double = first_mz - m_firstMzs.front();
  m_mzShifts.push_back(temp_double);
  if(temp_double < m_smallestMzShift)
    m_smallestMzShift = temp_double;

  if(temp_double > m_greatestMzShift)
    m_greatestMzShift = temp_double;

  double last_mz = mass_spectrum.back().x;
  m_lastMzs.push_back(last_mz);
  // The maximum m/z value

  // qDebug() << "Mass spectrum's last m/z:" << last_mz;

  if(last_mz > m_maxMz)
    {
      // qDebug() << "Will update the precendent m_maxMz:" << m_maxMz <<
      // "value";
      m_maxMz = last_mz;
    }
  // else
  //{
  // qDebug() << "Not changing current m_maxMz:" << m_maxMz
  //<< "because last_mz:" << last_mz;
  //}

  // The current mass spectrum has data in it, as they were loaded from file
  // (that is, unmodified in any way). We want to compute some of the various
  // data about it. For that we need to first fill in a bin vector from it.

  std::vector<double> bins;

  // qDebug() << "Crafting bins for mass spectrum with size:" <<
  //     mass_spectrum.size();

  int binCount = spectrumBins(mass_spectrum, bins);
  if(mass_spectrum.size() > 1 && !binCount)
    qFatal() << "Programming error.";

  double sum;
  double average;
  double variance;
  double stdDeviation;
  double nonZeroSmallest;
  double smallest;
  double smallestMedian;
  double greatest;

  doubleVectorStatistics(bins,
                         &sum,
                         &variance,
                         &average,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);

  // The smallest step
  if(nonZeroSmallest < m_nonZeroSmallestStep)
    m_nonZeroSmallestStep = nonZeroSmallest;

  m_smallestSteps.push_back(smallest);
  if(smallest < m_smallestStep)
    m_smallestStep = smallest;

  // The greatest step
  m_greatestSteps.push_back(greatest);
  if(greatest > m_greatestStep)
    m_greatestStep = greatest;

  m_avgSteps.push_back(average);
  m_stdDevSteps.push_back(stdDeviation);
}

void
MsRunDataSetStats::incrementStatistics(
  const pappso::MassSpectrumCstSPtr mass_spectrum_csp)
{

  const pappso::MassSpectrum &mass_spectrum = *(mass_spectrum_csp.get());

  return incrementStatistics(mass_spectrum);
}

void
MsRunDataSetStats::merge(const MsRunDataSetStats &other)

{
  // qDebug();

  m_spectrumCount += other.m_spectrumCount;

  if(other.m_smallestSpectrumSize < m_smallestSpectrumSize)
    m_smallestSpectrumSize = other.m_smallestSpectrumSize;

  if(other.m_greatestSpectrumSize > m_greatestSpectrumSize)
    m_greatestSpectrumSize = other.m_greatestSpectrumSize;

  if(other.m_minMz < m_minMz)
    m_minMz = other.m_minMz;

  // qDebug() << "The stats to merge have m_maxMz:" << other.m_maxMz
  //<< "and the current is:" << m_maxMz;
  if(other.m_maxMz > m_maxMz)
    {
      m_maxMz = other.m_maxMz;

      // qDebug() << "Since other.m_maxMz > m_maxMz, updated m_maxMz to:"
      //<< m_maxMz;
    }

  if(other.m_smallestMzShift < m_smallestMzShift)
    m_smallestMzShift = other.m_smallestMzShift;

  if(other.m_greatestMzShift > m_greatestMzShift)
    m_greatestMzShift = other.m_greatestMzShift;

  if(other.m_nonZeroSmallestStep < m_nonZeroSmallestStep)
    m_nonZeroSmallestStep = other.m_nonZeroSmallestStep;

  if(other.m_smallestStep < m_smallestStep)
    m_smallestStep = other.m_smallestStep;

  if(other.m_greatestStep > m_greatestStep)
    m_greatestStep = other.m_greatestStep;

  // Deal with the vectors of values...

  // qDebug();

  m_spectrumSizes.insert(std::end(m_spectrumSizes),
                         other.m_spectrumSizes.begin(),
                         other.m_spectrumSizes.end());

  // qDebug();

  m_firstMzs.insert(
    std::end(m_firstMzs), other.m_firstMzs.begin(), other.m_firstMzs.end());

  // qDebug();

  m_lastMzs.insert(
    std::end(m_lastMzs), other.m_lastMzs.begin(), other.m_lastMzs.end());

  // qDebug();

  m_mzShifts.insert(
    std::end(m_mzShifts), other.m_mzShifts.begin(), other.m_mzShifts.end());

  // qDebug();

  m_smallestSteps.insert(std::end(m_smallestSteps),
                         other.m_smallestSteps.begin(),
                         other.m_smallestSteps.end());

  // qDebug();

  m_greatestSteps.insert(std::end(m_greatestSteps),
                         other.m_greatestSteps.begin(),
                         other.m_greatestSteps.end());

  // qDebug();

  m_avgSteps.insert(
    std::end(m_avgSteps), other.m_avgSteps.begin(), other.m_avgSteps.end());

  // qDebug();

  m_stdDevSteps.insert(std::end(m_stdDevSteps),
                       other.m_stdDevSteps.begin(),
                       other.m_stdDevSteps.end());
  // qDebug();
}

void
MsRunDataSetStats::consolidate()
{
  // qDebug();

  // Perform all the statistics on the vectors.

  double sum;
  double average;
  double variance;
  double stdDeviation;
  double nonZeroSmallest;
  double smallest;
  double smallestMedian;
  double greatest;

  // The spectrum size.
  doubleVectorStatistics(m_spectrumSizes,
                         &sum,
                         &average,
                         &variance,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);
  m_spectrumSizeAvg    = average;
  m_spectrumSizeStdDev = stdDeviation;

#if 0
			// Print out the vector of all the spectrum sizes, to check how the sizes of
			// the spectra change inside a mass spectrum vector.
			QString msg = QString("s of spectrum sizes:\n%1\n");
			double val;
			foreach(val, m_spectralDataStats.spectrumSizes)
				msg.append(QString("%1\n").arg(val));
			qDebug() << msg;
#endif

#if 0
			// Print out the vector of all the mz shift between spectra.
			QString msg = QString("s of mz shifts:\n%1\n");
			double val;
			foreach(val, m_spectralDataStats.mzShifts)
				msg.append(QString("%1\n").arg(val));
			qDebug() << msg;
#endif

  // The first mz value
  doubleVectorStatistics(m_firstMzs,
                         &sum,
                         &average,
                         &variance,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);
  m_firstMzAvg    = average;
  m_firstMzStdDev = stdDeviation;

  // The last mz value
  doubleVectorStatistics(m_lastMzs,
                         &sum,
                         &average,
                         &variance,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);
  m_lastMzAvg    = average;
  m_lastMzStdDev = stdDeviation;

  // The mz shift
  doubleVectorStatistics(m_mzShifts,
                         &sum,
                         &average,
                         &variance,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);
  m_mzShiftAvg    = average;
  m_mzShiftStdDev = stdDeviation;

  // The smallest step
  doubleVectorStatistics(m_smallestSteps,
                         &sum,
                         &average,
                         &variance,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);
  m_smallestStepMedian = smallestMedian;

  // qDebug() << "m_smallestStepMedian:" << m_smallestStepMedian;

  m_smallestStepAvg    = average;
  m_smallestStepStdDev = stdDeviation;

  // The greatest step
  doubleVectorStatistics(m_greatestSteps,
                         &sum,
                         &average,
                         &variance,
                         &stdDeviation,
                         &nonZeroSmallest,
                         &smallest,
                         &smallestMedian,
                         &greatest);
  m_greatestStepAvg    = average;
  m_greatestStepStdDev = stdDeviation;

  // QString text = toString();
  // qDebug().noquote() << text;
}

bool
MsRunDataSetStats::isValid()
{
  int errors = 0;

  // There must be at least one spectrum
  errors += (m_spectrumCount ? 0 : 1);
  errors += (m_spectrumSizes.size() ? 0 : 1);

  errors +=
    (m_smallestSpectrumSize == std::numeric_limits<double>::max() ? 1 : 0);

  errors += (m_minMz == std::numeric_limits<double>::max() ? 1 : 0);
  errors += (m_firstMzs.size() ? 0 : 1);
  errors += (m_maxMz == 0 ? 1 : 0);
  errors += (m_lastMzs.size() ? 0 : 1);

  errors += (m_smallestStep == std::numeric_limits<double>::max() ? 1 : 0);
  errors += (m_greatestStep == 0 ? 1 : 0);
  errors += (m_smallestSteps.size() ? 0 : 1);
  errors += (m_greatestSteps.size() ? 0 : 1);

  errors += (m_avgSteps.size() ? 0 : 1);
  errors += (m_stdDevSteps.size() ? 0 : 1);

  if(errors)
    qDebug() << "The statistics are not valid...";

  return !errors;
}

QString
MsRunDataSetStats::toString() const
{
  QString text = "Spectral data set statistics:\n";

  text.append(
    QString::asprintf("\tTotal number of spectra: %d\n"
                      "\tAverage of spectrum size: %.6f\n"
                      "\tStdDev of spectrum size: %.6f\n"
                      "\tMinimum m/z value: %.6f\n"
                      "\tMaximum m/z value: %.6f\n"
                      "\tAverage of first m/z value: %.6f\n"
                      "\tStdDev of first m/z value: %.6f\n"
                      "\tAverage of last m/z value: %.6f\n"
                      "\tStdDev of last m/z value: %.6f\n"
                      "\tMinimum m/z shift: %.6f\n"
                      "\tMaximum m/z shift: %.6f\n"
                      "\tAverage of m/z shift: %.6f\n"
                      "\tStdDev of m/z shift: %.6f\n"
                      "\tSmallest non-zero Delta of m/z (step): %.6f\n"
                      "\tSmallest Delta of m/z (step): %.6f\n"
                      "\tMedian of smallest Delta of m/z (step): %.6f\n"
                      "\tAverage of smallest Delta of m/z (step): %.6f\n"
                      "\tStdDev of smallest Delta of m/z (step): %.6f\n"
                      "\tGreatest Delta of m/z (step): %.6f\n"
                      "\tAverage of greatest Delta of m/z (step): %.6f\n"
                      "\tStdDev of greatest Delta of m/z (step): %.6f\n",
                      m_spectrumCount,
                      m_spectrumSizeAvg,
                      m_spectrumSizeStdDev,
                      m_minMz,
                      m_maxMz,
                      m_firstMzAvg,
                      m_firstMzStdDev,
                      m_lastMzAvg,
                      m_lastMzStdDev,
                      m_smallestMzShift,
                      m_greatestMzShift,
                      m_mzShiftAvg,
                      m_mzShiftStdDev,
                      m_nonZeroSmallestStep,
                      m_smallestStep,
                      m_smallestStepMedian,
                      m_smallestStepAvg,
                      m_smallestStepStdDev,
                      m_greatestStep,
                      m_greatestStepAvg,
                      m_greatestStepStdDev));

  return text;
}


} // namespace MineXpert
} // namespace MsXpS
