/**
 * \file pappsomspp/psm/xtandem/xtandemhyperscore.cpp
 * \date 16/8/2016
 * \author Olivier Langella
 * \brief process spectrum to compute X!Tandem hyperscore
 */

/*******************************************************************************
 * Copyright (c) 2016 Olivier Langella <Olivier.Langella@moulon.inra.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@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "xtandemspectrumprocess.h"
#include <QDebug>

namespace pappso
{

XtandemSpectrumProcess::XtandemSpectrumProcess()
  : m_filter_keep_greater(150), m_n_most_intense(100), m_filter_rescale(100), m_filter_highpass(0.9)
{
}

XtandemSpectrumProcess::XtandemSpectrumProcess(const XtandemSpectrumProcess &copy)
  : m_filter_keep_greater(copy.m_filter_keep_greater),
    m_n_most_intense(copy.m_n_most_intense),
    m_filter_rescale(copy.m_filter_rescale),
    m_filter_highpass(copy.m_filter_highpass)
{
  m_isRemoveIsotope              = copy.m_isRemoveIsotope;
  m_isExcludeParent_neutral_loss = copy.m_isExcludeParent_neutral_loss;
  m_neutralLossMass              = copy.m_neutralLossMass;
  m_neutralLossWindowDalton      = copy.m_neutralLossWindowDalton;

  m_isExcludeParent              = copy.m_isExcludeParent;
  m_isExcludeParent_lower_dalton = copy.m_isExcludeParent_lower_dalton;
  m_isExcludeParent_upper_dalton = copy.m_isExcludeParent_upper_dalton;
  m_isRefineSpectrumModel        = copy.m_isRefineSpectrumModel;
  _y_ions                        = copy._y_ions;     // Enums::PeptideIon::y
  _b_ions                        = copy._b_ions;     // Enums::PeptideIon::b
  _ystar_ions                    = copy._ystar_ions; // Enums::PeptideIon::ystar
  _bstar_ions                    = copy._bstar_ions; // Enums::PeptideIon::bstar
  _c_ions                        = copy._c_ions;     // Enums::PeptideIon::c
  _z_ions                        = copy._z_ions;     // Enums::PeptideIon::z
  _a_ions                        = copy._a_ions;     // Enums::PeptideIon::a
  _x_ions                        = copy._x_ions;     // CO2

  _astar_ions = copy._astar_ions; // Enums::PeptideIon::a
  _ao_ions    = copy._ao_ions;
  _bo_ions    = copy._bo_ions;
  _yo_ions    = copy._yo_ions;
}
XtandemSpectrumProcess::~XtandemSpectrumProcess()
{
}

void
XtandemSpectrumProcess::setMinimumMz(pappso_double minimum_mz)
{
  m_filter_keep_greater = FilterResampleKeepGreater(minimum_mz);
}
void
XtandemSpectrumProcess::setNmostIntense(unsigned int nmost_intense)
{
  m_n_most_intense = FilterGreatestY(nmost_intense);
}
void
XtandemSpectrumProcess::setDynamicRange(pappso::pappso_double dynamic_range)
{
  m_filter_rescale = FilterRescaleY(dynamic_range);
}

void
XtandemSpectrumProcess::setRemoveIsotope(bool remove_isotope)
{
  m_isRemoveIsotope = remove_isotope;
}

void
XtandemSpectrumProcess::setExcludeParent(bool exclude_parent)
{
  m_isExcludeParent = exclude_parent;
}
void
XtandemSpectrumProcess::setExcludeParentNeutralLoss(bool neutral_loss)
{
  m_isExcludeParent_neutral_loss = neutral_loss;
}
void
XtandemSpectrumProcess::setNeutralLossMass(pappso::pappso_double neutral_loss_mass)
{
  m_neutralLossMass = neutral_loss_mass;
}
void
XtandemSpectrumProcess::setNeutralLossWindowDalton(pappso_double neutral_loss_precision)
{
  m_neutralLossWindowDalton = neutral_loss_precision;
}


void
XtandemSpectrumProcess::setRefineSpectrumModel(bool refine)
{
  m_isRefineSpectrumModel = refine;
}

// FIXME: enumeration values 'bp' and 'yp' not handled in switch
void
XtandemSpectrumProcess::setIonScore(Enums::PeptideIon ion_type, bool compute_score)
{
  switch(ion_type)
    {
      case Enums::PeptideIon::y:
        _y_ions = compute_score;
        break;

      case Enums::PeptideIon::b:
        _b_ions = compute_score;
        break;

      case Enums::PeptideIon::ystar:
        _ystar_ions = compute_score;
        break;

      case Enums::PeptideIon::bstar:
        _bstar_ions = compute_score;
        break;

      case Enums::PeptideIon::yo:
        _yo_ions = compute_score;
        break;

      case Enums::PeptideIon::bo:
        _bo_ions = compute_score;
        break;

      case Enums::PeptideIon::z:
        _z_ions = compute_score;
        break;

      case Enums::PeptideIon::a:
        _a_ions = compute_score;
        break;

      case Enums::PeptideIon::astar:
        _astar_ions = compute_score;
        break;
      case Enums::PeptideIon::ao:
        _ao_ions = compute_score;
        break;
      case Enums::PeptideIon::c:
        _c_ions = compute_score;
        break;
      case Enums::PeptideIon::x:
        _x_ions = compute_score;
        break;

      case Enums::PeptideIon::bp:
      case Enums::PeptideIon::yp:
        break;
    }
}

pappso_double
XtandemSpectrumProcess::getMinimumMz() const
{
  return m_filter_keep_greater.getThresholdX();
}
unsigned int
XtandemSpectrumProcess::getNmostIntense() const
{
  return m_n_most_intense.getNumberOfPoints();
}
pappso::pappso_double
XtandemSpectrumProcess::getDynamicRange() const
{
  return m_filter_rescale.getDynamicRange();
}
bool
XtandemSpectrumProcess::getRemoveIsotope() const
{
  return m_isRemoveIsotope;
}
bool
XtandemSpectrumProcess::getExcludeParent() const
{
  return m_isExcludeParent;
}
bool
XtandemSpectrumProcess::getExcludeParentNeutralLoss() const
{
  return m_isExcludeParent_neutral_loss;
}
pappso::pappso_double
XtandemSpectrumProcess::getNeutralLossMass() const
{
  return m_neutralLossMass;
}
pappso_double
XtandemSpectrumProcess::getNeutralLossWindowDalton() const
{
  return m_neutralLossWindowDalton;
}

bool
XtandemSpectrumProcess::getRefineSpectrumModel() const
{
  return m_isRefineSpectrumModel;
}

// FIXME: enumeration values 'bp' and 'yp' not handled in switch
bool
XtandemSpectrumProcess::getIonScore(Enums::PeptideIon ion_type) const
{
  switch(ion_type)
    {
      case Enums::PeptideIon::y:
        return _y_ions;

      case Enums::PeptideIon::b:
        return _b_ions;

      case Enums::PeptideIon::ystar:
        return _ystar_ions;

      case Enums::PeptideIon::bstar:
        return _bstar_ions;

      case Enums::PeptideIon::yo:
        return _yo_ions;

      case Enums::PeptideIon::bo:
        return _bo_ions;

      case Enums::PeptideIon::z:
        return _z_ions;

      case Enums::PeptideIon::a:
        return _a_ions;

      case Enums::PeptideIon::astar:
        return _astar_ions;
      case Enums::PeptideIon::ao:
        return _ao_ions;

      case Enums::PeptideIon::c:
        return _c_ions;
      case Enums::PeptideIon::x:
        return _x_ions;
      default:
        break;
    }
  return false;
}

MassSpectrum
XtandemSpectrumProcess::process(const MassSpectrum &spectrum,
                                pappso_double parent_ion_mz,
                                unsigned int parent_charge) const
{
  qDebug() << " parent_charge==" << parent_charge;

  // 1) clean isotopes
  MassSpectrum spectrum_process(spectrum);
  if(m_isRemoveIsotope)
    {
      spectrum_process.massSpectrumFilter(FilterTandemDeisotope());
    }
  qDebug();
  // 2) remove parent ion mass
  if(m_isExcludeParent)
    {
      spectrum_process.massSpectrumFilter(MassSpectrumFilterResampleRemoveMzRange(MzRange(
        parent_ion_mz,
        PrecisionFactory::getDaltonInstance(m_isExcludeParent_lower_dalton / parent_charge),
        PrecisionFactory::getDaltonInstance(m_isExcludeParent_upper_dalton / parent_charge))));
    }
  qDebug();
  // 3) remove low masses
  // 4) normalization
  m_filter_keep_greater.filter(spectrum_process);
  qDebug() << spectrum_process.size();
  m_filter_rescale.filter(spectrum_process);
  qDebug() << spectrum_process.size();
  // m_filter_floor.filter(spectrum_process);
  m_filter_highpass.filter(spectrum_process);

  qDebug() << spectrum_process.size();
  // 5) remove neutral loss
  if(m_isExcludeParent_neutral_loss)
    {
      pappso_double parent_ion_mhplus =
        ((parent_ion_mz - (MHPLUS * parent_charge)) * parent_charge) + MHPLUS;

      MassSpectrumFilterResampleRemoveMzRange filter_parent(
        MzRange(parent_ion_mhplus - m_neutralLossMass,
                PrecisionFactory::getDaltonInstance(m_neutralLossWindowDalton)));

      filter_parent.filter(spectrum_process);
    }
  // 6) clean isotopes
  // 7) keep n most intense peaks
  qDebug() << spectrum_process.size() << " parent_charge==" << parent_charge;
  // return spectrum_process.massSpectrumFilter(m_filter_remove_c13)
  // .filter(m_nMostIntense);

  m_filter_remove_c13.filter(spectrum_process);
  m_n_most_intense.filter(spectrum_process);
  qDebug() << spectrum_process.size();
  return spectrum_process;
}


} // namespace pappso
