/**
 * \file pappsomspp/xicextractor/private/msrunxicextractorpwiz.cpp
 * \date 07/05/2018
 * \author Olivier Langella
 * \brief simple proteowizard based XIC extractor
 */

/*******************************************************************************
 * Copyright (c) 2018 Olivier Langella <Olivier.Langella@u-psud.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@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "msrunxicextractor.h"
#include <QDebug>
#include <QObject>

#include "../../pappsoexception.h"
#include "../../exception/exceptioninterrupted.h"
#include "../../processing/filters/filterresample.h"

namespace pappso
{


MsRunXicExtractor::MsRunXicExtractor(MsRunReaderSPtr &msrun_reader)
  : pappso::MsRunXicExtractorInterface(msrun_reader)
{

  MsRunXicExtractorReadPoints get_msrun_points(m_msrun_points);
  msp_msrun_reader.get()->readSpectrumCollection(get_msrun_points);

  std::sort(m_msrun_points.begin(),
            m_msrun_points.end(),
            [](const MsRunXicExtractorPoints &a,
               const MsRunXicExtractorPoints &b) { return a.rt < b.rt; });


  if(m_msrun_points.size() == 0)
    {
      throw pappso::PappsoException(
        QObject::tr("error extracting XIC: no MS level 1 in data file"));
    }
}
MsRunXicExtractor::~MsRunXicExtractor()
{
}


MsRunXicExtractor::MsRunXicExtractor(const MsRunXicExtractor &other)
  : MsRunXicExtractorInterface(other)
{
  m_msrun_points = other.m_msrun_points;
}


void
MsRunXicExtractor::protectedExtractXicCoordSPtrList(
  UiMonitorInterface &monitor,
  std::vector<XicCoordSPtr>::iterator it_xic_coord_list_begin,
  std::vector<XicCoordSPtr>::iterator it_xic_coord_list_end)
{

  // sort xic by mz:
  std::sort(it_xic_coord_list_begin,
            it_xic_coord_list_end,
            [](XicCoordSPtr &a, XicCoordSPtr &b) {
              return a.get()->rtTarget < b.get()->rtTarget;
            });

  for(auto it = it_xic_coord_list_begin; it != it_xic_coord_list_end; it++)
    {
      // XicCoord *p_xic_coord = sp_xic_coord.get();
      extractOneXicCoord(*(it->get()));
      monitor.count();
      if(monitor.shouldIstop())
        {
          throw pappso::ExceptionInterrupted(
            QObject::tr("Xic extraction process interrupted"));
        }
    }
}


void
MsRunXicExtractor::extractOneXicCoord(XicCoord &xic_coord)
{
  FilterResampleKeepXRange keep_range(xic_coord.mzRange.lower(),
                                      xic_coord.mzRange.upper());
  std::shared_ptr<Xic> msrunxic_sp = xic_coord.xicSptr;

  double rt_begin = xic_coord.rtTarget - m_retentionTimeAroundTarget;
  double rt_end   = xic_coord.rtTarget + m_retentionTimeAroundTarget;


  auto itpoints = m_msrun_points.begin();

  // find startint retention time :
  while((itpoints != m_msrun_points.end()) && (itpoints->rt < rt_begin))
    {
      itpoints++;
    }
  MassSpectrumSPtr spectrum;
  DataPoint peak;
  while((itpoints != m_msrun_points.end()) && (itpoints->rt <= rt_end))
    {
      spectrum =
        msp_msrun_reader.get()->massSpectrumSPtr(itpoints->spectrum_index);
      // qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
      // << spectrum->size(); spectrum->debugPrintValues();

      qDebug() << " spectrum->size()=" << spectrum->size();
      keep_range.filter(*(spectrum.get()));
      qDebug() << " spectrum->size()=" << spectrum->size();

      peak.x = itpoints->rt;

      if(m_xicExtractMethod == XicExtractMethod::max)
        {
          peak.y = 0;
          if(spectrum->size() > 0)
            {
              peak.y = maxYDataPoint(spectrum->begin(), spectrum->end())->y;

              qDebug() << " peak.y=" << peak.y
                       << " spectrum->size()=" << spectrum->size();
            }
        }
      else
        {
          peak.y = sumYTrace(spectrum->begin(), spectrum->end(), 0);
        }
      msrunxic_sp->push_back(peak);

      itpoints++;
    }
}

void
MsRunXicExtractor::getXicFromPwizMSDataFile(
  std::vector<Xic *> &xic_list,
  const std::vector<MzRange> &mass_range_list,
  pappso::pappso_double rt_begin,
  pappso::pappso_double rt_end)
{
  qDebug();

  std::vector<DataPoint> peak_for_mass;
  for(const MzRange &mass_range : mass_range_list)
    {
      peak_for_mass.push_back(DataPoint());
      qDebug() << " mass_range=" << mass_range.getMz();
    }


  qDebug();

  auto itpoints = m_msrun_points.begin();

  while((itpoints != m_msrun_points.end()) && (itpoints->rt < rt_begin))
    {
      itpoints++;
    }

  MassSpectrumCstSPtr spectrum;
  while((itpoints != m_msrun_points.end()) && (itpoints->rt <= rt_end))
    {
      spectrum =
        msp_msrun_reader.get()->massSpectrumCstSPtr(itpoints->spectrum_index);

      for(DataPoint &peak : peak_for_mass)
        {
          peak.x = itpoints->rt;
          peak.y = 0;
        }


      // iterate through the m/z-intensity pairs
      for(auto &&spectrum_point : *(spectrum.get()))
        {
          // qDebug() << "getXicFromPwizMSDataFile it->mz " << it->mz <<
          // " it->intensity" << it->intensity;
          for(std::size_t i = 0; i < mass_range_list.size(); i++)
            {
              if(mass_range_list[i].contains(spectrum_point.x))
                {
                  if(m_xicExtractMethod == XicExtractMethod::max)
                    {
                      if(peak_for_mass[i].y < spectrum_point.y)
                        {
                          peak_for_mass[i].y = spectrum_point.y;
                        }
                    }
                  else
                    {
                      peak_for_mass[i].y += spectrum_point.y;
                    }
                }
            }
        }

      for(std::size_t i = 0; i < mass_range_list.size(); i++)
        {
          // qDebug() << "getXicFromPwizMSDataFile push_back " <<
          // peak_for_mass[i].rt;
          xic_list[i]->push_back(peak_for_mass[i]);
        }

      itpoints++;
    }


  qDebug();
} // namespace pappso


} // namespace pappso
