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


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

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


namespace MsXpS
{

namespace libXpertMass
{

/*!
\class MsXpS::libXpertMass::Ponderable
\inmodule libXpertMass
\ingroup PolChemDefBuildingdBlocks
\inheaderfile Ponderable.hpp

\brief The Ponderable class provides an abstraction for any chemical entity
having a monoisotopic and an average mass.

Functions are provided to modify the member masses.

\sa Modif, Monomer
*/


/*!
  \variable MsXpS::libXpertMass::Ponderable::m_mono

  \brief The monoisotopic mass.
*/


/*!
   \variable MsXpS::libXpertMass::Ponderable::m_avg

   \brief The average mass.
*/

/*!
   \brief Constructs a ponderable initializing its masses with \a mono and
    \a avg.
*/
  Ponderable::Ponderable(double mono, double avg)
  {
    m_mono = mono;
    m_avg  = avg;
  }

/*!
   \brief Constructs a ponderable initializing it using \a other.
*/
  Ponderable::Ponderable(const Ponderable &other)
    : m_mono(other.m_mono), m_avg(other.m_avg)
  {
  }

/*!
   \brief Destructs the ponderable.
*/
  Ponderable::~Ponderable()
  {
  }

/*!
   \brief Assigns to this Ponderable' member data the values in \a
other.

  Returns a reference to this Ponderable
*/
  Ponderable &
  Ponderable::operator=(const Ponderable &other)
  {
    if(&other == this)
      return *this;

    m_mono = other.m_mono;
    m_avg  = other.m_avg;

    return *this;
  }

/*!
  \brief Initializes the member data using \a mono and \a avg.
  */
  void
  Ponderable::setMasses(double mono, double avg)
  {
    m_mono = mono;
    m_avg  = avg;
  }

/*!
  \brief Initializes the member data using \a mass.

  The member datum that is initialized depends on the value of \a type.
*/
  void
  Ponderable::setMass(double mass, MassType type)
  {
    if(type & MassType::MASS_MONO)
      m_mono = mass;
    else if(type & MassType::MASS_AVG)
      m_avg = mass;

    return;
  }

/*!
  \brief Add to the member data the mass value in \a mass.

  The member datum that is modified depends on the value of \a type.
*/
  void
  Ponderable::incrementMass(double mass, MassType type)
  {
    if(type & MassType::MASS_MONO)
      m_mono += mass;
    else if(type & MassType::MASS_AVG)
      m_avg += mass;

    return;
  }

/*!
  \brief Sets the \a mono and \a avg to the corresponding member data values.

  The pointer arguments cannot be nullptr.
*/
  void
  Ponderable::masses(double *mono, double *avg) const
  {
    Q_ASSERT(mono != nullptr && avg != nullptr);

    *mono = m_mono;
    *avg  = m_avg;
  }

/*!
  \brief Returns the mass depending on the \a type.
*/
  double
  Ponderable::mass(MassType type) const
  {
    if(type == MassType::MASS_MONO)
      return m_mono;

    return m_avg;
  }

/*!
  \brief Sets the member data masses to 0.0.
  */
  void
  Ponderable::clearMasses()
  {
    m_mono = 0.0;
    m_avg  = 0.0;
  }

/*!
  \brief Sets the monoisotopic mass to \a mass.
*/
  void
  Ponderable::setMono(double mass)
  {
    m_mono = mass;
  }

/*!
  \brief Sets the monoisotopic mass to \a mass.

  The \a mass string is converted to double.

  Returns true if the conversion succceeded, false otherwise.
*/
  bool
  Ponderable::setMono(const QString &mass)
  {
    bool ok = false;

    double value = mass.toDouble(&ok);

    if(!ok)
      return false;

    m_mono = value;

    return true;
  }

/*!
  \brief Increments the monoisotopic mass by adding \a mass.
*/
  void
  Ponderable::incrementMono(double mass)
  {
    m_mono += mass;
  }

/*!
  \brief Decrements the monoisotopic mass by subtracting \a mass.
*/
  void
  Ponderable::decrementMono(double mass)
  {
    m_mono -= mass;
  }

/*!
  \brief Returns the monoisotopic mass.
*/
  double
  Ponderable::mono() const
  {
    return m_mono;
  }

/*!
  \brief Returns a reference to the monoisotopic mass.
*/
  double &
  Ponderable::rmono()
  {
    return m_mono;
  }

/*!
  \brief Returns a string representing the monoisotopic mass using \a
decimalPlaces for the precision.
*/
  QString
  Ponderable::monoString(int decimalPlaces) const
  {
    if(decimalPlaces < 0)
      decimalPlaces = 0;

    QString mass;
    mass.setNum(m_mono, 'f', decimalPlaces);

    return mass;
  }

/*!
  \brief Sets the average mass to \a mass.
*/
  void
  Ponderable::setAvg(double mass)
  {
    m_avg = mass;
  }

/*!
  \brief Sets the average mass to \a mass.

  The \a mass string is converted to double.

  Returns true if the conversion succceeded, false otherwise.
*/
  bool
  Ponderable::setAvg(const QString &mass)
  {
    bool ok = false;

    double value = mass.toDouble(&ok);

    if(!ok)
      return false;

    m_avg = value;

    return true;
  }

/*!
  \brief Increments the average mass by adding \a mass.
*/
  void
  Ponderable::incrementAvg(double mass)
  {
    m_avg += mass;
  }

/*!
  \brief Decrements the average mass by subtracting \a mass.
*/
  void
  Ponderable::decrementAvg(double mass)
  {
    m_avg -= mass;
  }

/*!
  \brief Returns the average mass.
*/
  double
  Ponderable::avg() const
  {
    return m_avg;
  }

/*!
  \brief Returns a reference to the average mass.
*/
  double &
  Ponderable::ravg()
  {
    return m_avg;
  }

/*!
  \brief Returns a string representing the average mass using \a
decimalPlaces for the precision.
*/
  QString
  Ponderable::avgString(int decimalPlaces) const
  {
    if(decimalPlaces < 0)
      decimalPlaces = 0;

    QString mass;
    mass.setNum(m_avg, 'f', decimalPlaces);

    return mass;
  }

/*!
  Returns true if \a other and this ponderable have the same masses, false
otherwise.
*/
  bool
  Ponderable::operator==(const Ponderable &other) const
  {
    if(m_mono == other.m_mono && m_avg == other.m_avg)
      return true;

    return false;
  }

/*!
  Returns true if \a other and this ponderable have at least one differing mass,
false otherwise.
*/
  bool
  Ponderable::operator!=(const Ponderable &other) const
  {
    if(m_mono != other.m_mono || m_avg != other.m_avg)
      {
        // qDebug() << __FILE__ << __LINE__
        //          << "m_mono:" << m_mono
        //          << "/"
        //          << "other.m_mono:" << other.m_mono
        //          << "--"
        //          << "m_avg:" << m_avg
        //          << "/"
        //          << "other.m_avg:" << other.m_avg;

        return true;
      }

    return false;
  }


  bool
  Ponderable::calculateMasses()
  {
    return true;
  }

  /*!
    \brief Increase the member masses by adding either \a mono and or \a avg
compounded by \a times.

    The monoisotopic mass is increased if \a mono is not nullptr. The \a mono
value is compounded by \a times and the result is added to the member
monoisotopic datum.

     The average mass is increased if \a avg is not nullptr. The \a avg
value is compounded by \a times and the result is added to the member
average datum.

    Always returns true.
  */
  bool
  Ponderable::accountMasses(double *mono, double *avg, int times) const
  {
    if(mono != nullptr)
      *mono += m_mono * times;

    if(avg != nullptr)
      *avg += m_avg * times;

    return true;
  }

} // namespace libXpertMass

} // namespace MsXpS
