/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright 2009--2026 by 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
 */


/////////////////////// Local includes
#include "MsXpS/libXpertMassCore/CleavageConfig.hpp"

namespace MsXpS
{
namespace libXpertMassCore
{


/*!
\class MsXpS::libXpertMassCore::CleavageConfig
\inmodule libXpertMassCore
\ingroup PolChemDefAqueousChemicalReactions
\inheaderfile CleavageConfig.hpp

\brief The CleavageConfig class derives from CleavageAgent to  provide a model
for specifying aqueous cleavage specifications (patterns) of \l{Polymer}
\l{Sequence}s along with instructions on the way the cleavage must occur.

Cleavage agent specifications determine the specificity of cleavage in a polymer
sequence using a simple syntax. For example, Trypsin is able to cleave after
lysyl and arginyl residues. Its cleavage pattern is thus "Lys/;Arg/". However,
it is known that Trypsin fails to cleave after Lys if that monomer is followed
by a Prolyl residue, thus the complete cleavage agent pattern specification for
Trypsin is the following: "Lys/;Arg/;-Lys/Pro".

A cleavage agent specification might not be enough information to determine the
manner in which a polymer is cleaved. Cleavage rules might be required to refine
the specification. A cleavage agent specification might hold as many cleavage
rules as required.

\sa CleavageMotif, CleavageRule
*/


/*!
\variable MsXpS::libXpertMassCore::CleavageConfig::m_partials

\brief The partial cleavages accepted.
*/

/*!
\variable MsXpS::libXpertMassCore::CleavageConfig::m_startIonizeLevel

\brief The first ionization level of the range.
*/

/*!
\variable MsXpS::libXpertMassCore::CleavageConfig::m_stopIonizeLevel

\brief The last ionization level of the range.
*/


/*!
\variable MsXpS::libXpertMassCore::CleavageConfig::m_sequenceEmbedded

\brief Tells if the sequence of the obtained Oligomer instance need to embed
their sequence.
*/


/*!
\brief Constructs an empty CleavageConfig instance.
*/
CleavageConfig::CleavageConfig(QObject *parent): CleavageAgent(parent)
{
}

/*!
\brief Constructs a CleavageConfig instance using a full set of parameters.

\list
\a pol_chem_def_csp: the polymer chemistry definition.

\a name: the name of CleavageAgent;

\a pattern: the cleavage pattern of the CleavageAgent;

\a partials: the partial cleavages;

\a is_sequence_embedded: indicates if the Oligomer sequence needs to be stored.
\endlist
*/
CleavageConfig::CleavageConfig(PolChemDefCstSPtr pol_chem_def_csp,
                               const QString &name,
                               const QString &pattern,
                               int partials,
                               bool is_sequence_embedded,
                               QObject *parent)
  : CleavageAgent(pol_chem_def_csp, name, pattern, parent),
    m_partials(partials),
    m_sequenceEmbedded(is_sequence_embedded)
{
}

/*!
\brief Constructs a CleavageConfig instance starting using a limited set of
parameters.

\list
\a cleavage_agent: CleavageAgent to be used to initialize the base class.

\a partials: the partial cleavages;

\a is_sequence_embedded: indicates if the Oligomer sequence needs to be stored.
\endlist
*/
CleavageConfig::CleavageConfig(const CleavageAgent &cleavage_agent,
                               int partials,
                               bool is_sequence_embedded,
                               QObject *parent)
  : CleavageAgent(cleavage_agent, parent),
    m_partials(partials),
    m_sequenceEmbedded(is_sequence_embedded)
{
}

/*!
\brief Constructs a CleavageConfig instance as a copy of \a other
*/
CleavageConfig::CleavageConfig(const CleavageConfig &other, QObject *parent)
  : CleavageAgent(other, parent),
    m_partials(other.m_partials),
    m_startIonizeLevel(other.m_startIonizeLevel),
    m_stopIonizeLevel(other.m_stopIonizeLevel),
    m_sequenceEmbedded(other.m_sequenceEmbedded)
{
}

/*!
\brief Destructs this CleavageConfig instance.
*/
CleavageConfig::~CleavageConfig()
{
}

/*!
\brief Initializes this CleavageConfig instance using \a other.

If no initialization error occurred, return true, false otherwise.
*/
bool
CleavageConfig::initialize(const CleavageConfig &other)
{
  // That call fatal-fails, no need to check bool return value.
  bool ok = CleavageAgent::initialize(other);

  if(!ok)
    qDebug() << "Failed to initalize the CleavageConfig instance.";

  m_partials         = other.m_partials;
  m_startIonizeLevel = other.m_startIonizeLevel;
  m_stopIonizeLevel  = other.m_stopIonizeLevel;
  m_sequenceEmbedded = other.m_sequenceEmbedded;

  return ok;
}

/*!
\brief Sets this instance's CleavageAgent base class to \a cleavage_agent.

Returns true the CleavageAgent initialization succeeded, false otherwise.
*/
bool
CleavageConfig::setCleavageAgent(const CleavageAgent &cleavage_agent)
{
  bool ok = CleavageAgent::initialize(cleavage_agent);

  if(!ok)
    qDebug() << "Failed to initalize the CleavageConfig instance.";

  return ok;
}

/*!
\brief Set the partial cleavages to \a value.
*/
void
CleavageConfig::setPartials(int value)
{
  Q_ASSERT(value >= 0);

  m_partials = value;
}

/*!
\brief Returns the partial cleavages.
*/
int
CleavageConfig::getPartials() const
{
  return m_partials;
}

/*!
\brief Sets the ionization start level to \a value.
*/
void
CleavageConfig::setStartIonizeLevel(int value)
{
  int local = (value < 0) ? abs(value) : value;

  if(local <= m_stopIonizeLevel)
    {
      m_startIonizeLevel = local;
    }
  else
    {
      m_startIonizeLevel = m_stopIonizeLevel;
      m_stopIonizeLevel  = local;
    }
}

/*!
\brief Returns the ionization start level.
*/
int
CleavageConfig::getStartIonizeLevel() const
{
  return m_startIonizeLevel;
}

/*!
\brief Sets the ionization stop level to \a value.
*/
void
CleavageConfig::setStopIonizeLevel(int value)
{
  int local = (value < 0) ? abs(value) : value;

  if(local > m_startIonizeLevel)
    {
      m_stopIonizeLevel = local;
    }
  else
    {
      m_startIonizeLevel = m_stopIonizeLevel;
      m_stopIonizeLevel  = local;
    }
}

/*!
\brief Returns the ionization stop level.
*/
int
CleavageConfig::getStopIonizeLevel() const
{
  return m_stopIonizeLevel;
}

/*!
\brief Sets both the ionization start and stop levels to \a value1 and \a
value2, respectively.
*/
void
CleavageConfig::setIonizeLevels(int value1, int value2)
{
  if(abs(value1) <= abs(value2))
    {
      m_startIonizeLevel = abs(value1);
      m_stopIonizeLevel  = abs(value2);
    }
  else
    {
      m_startIonizeLevel = abs(value2);
      m_stopIonizeLevel  = abs(value1);
    }
}

/*!
\brief Sets the sequence embedded boolean value to \a is_sequence_embedded.
*/
void
CleavageConfig::setSequenceEmbedded(bool is_sequence_embedded)
{
  m_sequenceEmbedded = is_sequence_embedded;
}

/*!
\brief Returns the sequence embedded boolean value.
*/
bool
CleavageConfig::isSequenceEmbedded() const
{
  return m_sequenceEmbedded;
}

//////////////// OPERATORS /////////////////////

/*!
\brief Returns true if this CleavageConfig instance and \a other are identical,
false otherwise.
\sa operator!=()
*/
bool
CleavageConfig::operator==(const CleavageConfig &other) const
{
  if(&other == this)
    return true;

  if(CleavageAgent::operator!=(other) || m_partials != other.m_partials ||
     m_startIonizeLevel != other.m_startIonizeLevel ||
     m_stopIonizeLevel != other.m_stopIonizeLevel ||
     m_sequenceEmbedded != other.m_sequenceEmbedded)
    return false;

  return true;
}

/*!
\brief Returns true if this instance and \a other differ, false otherwise.
Returns the negative value of opearator==().
\sa operator==()
*/
bool
CleavageConfig::operator!=(const CleavageConfig &other) const
{
  return !operator==(other);
}

void
CleavageConfig::registerJsConstructor(QJSEngine *engine)
{
  if(!engine)
    {
      qDebug() << "Cannot register CleavageConfig class: engine is null";
      return;
    }

  // Register the meta object as a constructor

  QJSValue jsMetaObject =
    engine->newQMetaObject(&CleavageConfig::staticMetaObject);
  engine->globalObject().setProperty("CleavageConfig", jsMetaObject);
}


} // namespace libXpertMassCore
} // namespace MsXpS
