/**
 * \file pappsomspp/processing/filters/filtercomplementionenhancer.cpp
 * \date 21/08/2020
 * \author Olivier Langella
 * \brief enhance ion intensity of ion fragment complement
 */

/*******************************************************************************
 * Copyright (c) 2020 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/>.
 *
 ******************************************************************************/

#include "filtercomplementionenhancer.h"
#include "pappsomspp/core/exception/exceptionnotrecognized.h"

using namespace pappso;

FilterComplementIonEnhancer::FilterComplementIonEnhancer(double target_mz,
                                                         PrecisionPtr precision_ptr)
  : m_targetMzSum(target_mz), m_precisionPtr(precision_ptr)
{
}

FilterComplementIonEnhancer::FilterComplementIonEnhancer(const FilterComplementIonEnhancer &other)
  : m_targetMzSum(other.m_targetMzSum), m_precisionPtr(other.m_precisionPtr)
{
}

pappso::FilterComplementIonEnhancer::FilterComplementIonEnhancer(
  const pappso::QualifiedMassSpectrum &qmass_spectrum, pappso::PrecisionPtr precision_ptr)
  : m_targetMzSum(
      ((qmass_spectrum.getPrecursorMz() -
        (qmass_spectrum.getPrecursorCharge() * MHPLUS / qmass_spectrum.getPrecursorCharge())) *
         qmass_spectrum.getPrecursorCharge() +
       (MHPLUS + MHPLUS))),
    m_precisionPtr(precision_ptr)
{
}

pappso::FilterComplementIonEnhancer::FilterComplementIonEnhancer(const QString &strBuildParams)
{
  buildFilterFromString(strBuildParams);
}

void
pappso::FilterComplementIonEnhancer::buildFilterFromString(const QString &strBuildParams)
{
  //"complementIonEnhancer|456.567;0.02dalton"
  if(strBuildParams.startsWith("complementIonEnhancer|"))
    {
      QStringList params = strBuildParams.split("|").back().split(";");

      m_targetMzSum     = params.at(0).toDouble();
      QString precision = params.at(1);
      m_precisionPtr    = PrecisionFactory::fromString(
        precision.replace("dalton", " dalton").replace("ppm", " ppm").replace("res", " res"));
    }
  else
    {
      throw pappso::ExceptionNotRecognized(
        QString("building FilterComplementIonEnhancer from string %1 is not possible")
          .arg(strBuildParams));
    }
}


QString
pappso::FilterComplementIonEnhancer::name() const
{
  return "complementIonEnhancer";
}


QString
pappso::FilterComplementIonEnhancer::toString() const
{
  QString strCode = QString("%1|%2;%3")
                      .arg(name())
                      .arg(QString::number(m_targetMzSum, 'g', 15))
                      .arg(m_precisionPtr->toString());
  strCode.replace(" ", "");

  return strCode;
}

FilterComplementIonEnhancer::~FilterComplementIonEnhancer()
{
}

pappso::Trace &
pappso::FilterComplementIonEnhancer::filter(pappso::Trace &data_points) const
{

  auto it_end = data_points.end();
  std::sort(data_points.begin(), it_end, [](const DataPoint &a, const DataPoint &b) {
    return (a.y > b.y);
  });

  for(auto it = data_points.begin(); it != it_end; it++)
    {
      double mz_complement = m_targetMzSum - it->x;
      if(mz_complement > 0)
        {
          MzRange mz_range(mz_complement, m_precisionPtr);
          enhanceComplementMassInRange(it->y, mz_range.lower(), mz_range.upper(), it, it_end);
        }
    }

  data_points.sortX();
  return data_points;
}


void
pappso::FilterComplementIonEnhancer::enhanceComplementMassInRange(
  double new_intensity,
  double mz_lower_bound,
  double mz_upper_bound,
  std::vector<DataPoint>::iterator it_begin,
  std::vector<DataPoint>::iterator it_end) const
{
  for(std::vector<DataPoint>::iterator it = it_begin; it != it_end; it++)
    {
      if((it->x >= mz_lower_bound) && (it->x <= mz_upper_bound))
        {
          if(it->y < new_intensity)
            {
              it->y = new_intensity;
            }
        }
    }
}
