/* 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 <QDebug>
#include <QScriptEngine>


/////////////////////// Local includes
#include <libmass/MassSpectrumJsPrototype.hpp>
#include <libmass/MassSpectrum.hpp>
#include <libmass/DataPointJs.hpp>

#include <globals/globals.hpp>


namespace msXpSlibmass
{

/*/js/ Class: MassSpectrum
 */

MassSpectrumJsPrototype::MassSpectrumJsPrototype(QObject *parent)
  : QObject(parent)
{
}


MassSpectrumJsPrototype::~MassSpectrumJsPrototype()
{
}


MassSpectrum *
MassSpectrumJsPrototype::thisMassSpectrum() const
{
  MassSpectrum *massSpectrum =
    qscriptvalue_cast<MassSpectrum *>(thisObject().data());

  if(massSpectrum == Q_NULLPTR)
    qFatal(
      "Fatal error at %s@%d -- %s. "
      "thisMassSpectrum() would return Q_NULLPTR."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);

  return massSpectrum;
}


int
MassSpectrumJsPrototype::initialize()
{
  qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  // Depending on the various parameters, we will choose the proper
  // initializing function.

  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
           << "argCount: " << argCount;

  if(argCount == 1)
    {
      return initializeOneArgument();
    }
  else if(argCount == 2)
    {
      return initializeTwoArguments();
    }
  else if(argCount == 4)
    {
      return initializeFourArguments();
    }

  return -1;
}


int
MassSpectrumJsPrototype::initializeOneArgument()
{
  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  if(argCount != 1)
    qFatal(
      "Fatal error at %s@%d -- %s(). "
      "Programming error."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);


  QScriptValue arg = ctx->argument(0);

  if(arg.isString())
    return thisMassSpectrum()->initialize(qscriptvalue_cast<QString>(arg));
  else
    {
      // The other single-arg initializations are with Trace or MassSpectrum.

      QVariant variant = arg.data().toVariant();

      if(!variant.isValid())
        {
          qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
                   << "Variant is not valid";

          ctx->throwError(
            "Syntax error: function takes either one Trace object or a "
            "MassSpectrum object.");

          return -1;
        }

      if(variant.userType() == QMetaType::type("msXpSlibmass::Trace"))
        {
          Trace trace(qscriptvalue_cast<Trace>(arg));

          // Essential is to delete all the DataPoint objects, because we are
          // not actually combiining, but we are initializing!

          thisMassSpectrum()->deleteDataPoints();

          /*/js/
           * MassSpectrum.initialize(other)
           *
           * Initialize this MassSpectrum object with a <Trace> object
           *
           * other: <Trace> object
           *
           * Ex:
           *
           * var t1 = new Trace;
           * t1.initialize([123.321,456.654,789.987],[147.741, 258.852,
           * 369.963]); t1.asText();
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           * var ms1 = new MassSpectrum();
           * ms1.initialize(t1);
           * ms1.asText();
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           */

          return thisMassSpectrum()->combine(trace);
        }

      if(variant.userType() == QMetaType::type("msXpSlibmass::MassSpectrum"))
        {
          MassSpectrum massSpectrum(qscriptvalue_cast<MassSpectrum>(arg));

          // Essential is to delete all the DataPoint objects, because we are
          // not actually combiining, but we are initializing!

          thisMassSpectrum()->deleteDataPoints();

          /*/js/
           * MassSpectrum.initialize(other)
           *
           * Initialize this MassSpectrum object with a <MassSpectrum> object
           *
           * other: <MassSpectrum> object
           *
           * Ex:
           *
           * var ms1 = new MassSpectrum();
           * ms1.initialize([123.321,456.654,789.987],[147.741, 258.852,
           * 369.963]); ms1.asText();
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           * var ms2 = new MassSpectrum();
           * ms2.initialize(ms1);
           * ms2.asText();
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           */

          return thisMassSpectrum()->combine(massSpectrum);
        }
    }

  return -1;
}


int
MassSpectrumJsPrototype::initializeTwoArguments()
{
  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  if(argCount != 2)
    qFatal(
      "Fatal error at %s@%d -- %s(). "
      "Programming error."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);

  QScriptValue arg1 = ctx->argument(0);
  QScriptValue arg2 = ctx->argument(1);

  // For the initialization with two arguments, these arguments might be the
  // mzList and iList. Nothing else.

  if(!arg1.isArray() || !arg2.isArray())
    {
      qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
               << "One or two arguments is/are not of the Array type.";

      ctx->throwError(
        "Syntax error: the two arguments must be of the Array type, mzArray "
        "and iArray.");

      return -1;
    }

  /*/js/
   * MassSpectrum.initialize(mzArray, iArray)
   *
   * Initialize this MassSpectrum object with two <Array> of numerical
   * values
   *
   * mzArray: <Array> object containing the m/z values of the spectrum
   * iArray: <Array> object containing the intensity values of the spectrum
   *
   * Ex:
   *
   * var ms1 = new MassSpectrum;
   *
   * var mzArray = [123.321,456.654,789.987];
   * var iArray = [147.741, 258.852, 369.963];
   *
   * ms1.initialize(mzArray, iArray);
   *
   * ms1.asText(); // --> output is:
   *
   * 123.3210000000 147.7410000000
   * 456.6540000000 258.8520000000
   * 789.9870000000 369.9630000000
   */

  QList<double> mzList = qscriptvalue_cast<QList<double>>(arg1);
  QList<double> iList  = qscriptvalue_cast<QList<double>>(arg2);

  return thisMassSpectrum()->Trace::initialize(mzList, iList);
}


int
MassSpectrumJsPrototype::initializeFourArguments()
{
  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  if(argCount != 4)
    qFatal(
      "Fatal error at %s@%d -- %s(). "
      "Programming error."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);

  QScriptValue arg1 = ctx->argument(0);
  QScriptValue arg2 = ctx->argument(1);
  QScriptValue arg3 = ctx->argument(2);
  QScriptValue arg4 = ctx->argument(3);

  // For the initialization with four arguments, these arguments might be the
  // mzList and iList, the mzStart and mzEnd. Nothing else.

  if(!arg1.isArray() || !arg2.isArray())
    {
      qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
               << "One or two arguments is/are not of the Array type.";

      ctx->throwError(
        "Syntax error: the first two arguments must be of the Array type: "
        "mzArray and iArray.");

      return -1;
    }

  if(!arg3.isNumber() || !arg4.isNumber())
    {
      qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
               << "One or two arguments is/are not of the Number type.";

      ctx->throwError(
        "Syntax error: the last two arguments must be of the Number type: "
        "mzStart and mzEnd.");

      return -1;
    }

  QList<double> mzList = qscriptvalue_cast<QList<double>>(arg1);
  QList<double> iList  = qscriptvalue_cast<QList<double>>(arg2);
  double mzStart       = qscriptvalue_cast<double>(arg3);
  double mzEnd         = qscriptvalue_cast<double>(arg4);

  /*/js/
   * MassSpectrum.initialize(mzArray, iArray, mzStart, mzEnd)
   *
   * Initialize this MassSpectrum object with two <Array> of numerical
   * values and two <Number> entities delimiting a range of acceptable m/z
   * values.
   *
   * mzArray: <Array> object containing the m/z values of the spectrum
   * iArray: <Array> object containing the intensity values of the spectrum
   * mzStart: m/z value used to filter the data points to be used for the
   * initialization (the start of the acceptable m/z range)
   * mzEnd: m/z value used to filter the data points to be crafted for the
   * initialization (the end of the acceptable m/z range)
   *
   * Ex:
   *
   * var ms1 = new MassSpectrum;
   *
   * var mzArray = [123.321,456.654,789.987];
   * var iArray = [147.741, 258.852, 369.963];
   *
   * ms1.initialize(mzArray, iArray, 122.231, 789.986); // range:
   * [122.231-789.986]
   *
   * ms1.asText(); // --> output is:
   *
   * 123.3210000000 147.7410000000
   * 456.6540000000 258.8520000000
   */

  return thisMassSpectrum()->Trace::initialize(mzList, iList, mzStart, mzEnd);
}


/*/js/
 * MassSpectrum.mzArray()
 *
 * Return a list of <Number> entities corresponding to all the m/z values of
 * the spectrum
 *
 * Ex:
 *
 * var ms1 = new MassSpectrum;
 *
 * var mzArray = [123.321,456.654,789.987];
 * var iArray = [147.741, 258.852, 369.963];
 *
 * ms1.initialize(mzArray, iArray, 122.231, 789.986); // range:
 * [122.231-789.986]
 *
 * ms1.asText(); // --> output is:
 *
 * 123.3210000000 147.7410000000
 * 456.6540000000 258.8520000000
 *
 * ms1.mzArray(); --> output is:
 * 123.321,456.654
 */
QList<double>
MassSpectrumJsPrototype::mzArray() const
{
  return thisMassSpectrum()->keyList();
}


/*/js/
 * MassSpectrum.iArray()
 *
 * Return a list of <Number> entities corresponding to all the intensity values
 * of the spectrum
 *
 * Ex:
 *
 * var ms1 = new MassSpectrum;
 *
 * var mzArray = [123.321,456.654,789.987];
 * var iArray = [147.741, 258.852, 369.963];
 *
 * ms1.initialize(mzArray, iArray, 122.231, 789.986); // range:
 * [122.231-789.986]
 *
 * ms1.asText(); // --> output is:
 *
 * 123.3210000000 147.7410000000
 * 456.6540000000 258.8520000000
 *
 * ms1.iArray(); --> output is:
 * 147.741,258.852
 */
QList<double>
MassSpectrumJsPrototype::iArray() const
{
  return thisMassSpectrum()->valList();
}


/*/js/
 * MassSpectrum.asText()
 *
 * Return the data points of the spectrum in <String> object. The format of the
 * string is of the kind <m/z>,<intensity>, one data point per line.
 *
 * Ex:
 *
 * var ms1 = new MassSpectrum;
 *
 * var mzArray = [123.321,456.654,789.987];
 * var iArray = [147.741, 258.852, 369.963];
 *
 * ms1.initialize(mzArray, iArray, 122.231, 789.986); // range:
 * [122.231-789.986]
 *
 * ms1.asText(); // --> output is:
 *
 * 123.3210000000 147.7410000000
 * 456.6540000000 258.8520000000
 */
QString
MassSpectrumJsPrototype::asText() const
{
  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  double rangeStart = -1;
  double rangeEnd   = -1;

  if(argCount != 0 && argCount != 2)
    {
      ctx->throwError(
        "Syntax error: function asText() takes either 0 or 2 numbers as index "
        "arguments.");
      return QString();
    }
  else if(argCount == 2)
    {
      QScriptValue arg1 = ctx->argument(0);
      QScriptValue arg2 = ctx->argument(1);

      if(!arg1.isNumber() || !arg2.isNumber())
        {
          ctx->throwError(
            "Syntax error: function asText() takes either 0 or 2 numbers as "
            "index arguments.");
          return QString();
        }

      rangeStart = qscriptvalue_cast<double>(arg1);
      rangeEnd   = qscriptvalue_cast<double>(arg2);
    }

  // Finally, do the work.

  return thisMassSpectrum()->asText(rangeStart, rangeEnd);
}

/*/js/
 * MassSpectrum.tic()
 *
 * Return the total ion current calculated for this MassSpectrum object
 *
 * Ex:
 *
 * var ms1 = new MassSpectrum;
 * ms1.initialize([123.321, 456.654, 789.987], [147.741, 258.852, 369.963]);
 * ms1.asText();
 * ms1.tic(); // --> 776.556
 */
double
MassSpectrumJsPrototype::tic() const
{
  // Either there is no argument, or there must be two arguments:
  // mzRangeStart and mzRangeEnd

  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  if(argCount == 0)
    return thisMassSpectrum()->valSum();
  else if(argCount == 2)
    {
      QScriptValue arg1 = ctx->argument(0);
      QScriptValue arg2 = ctx->argument(1);

      if(!arg1.isNumber() || !arg2.isNumber())
        {
          ctx->throwError(
            "Syntax error: function tic() takes 2 numbers as arguments.");

          return -1;
        }

      double mzRangeStart = qscriptvalue_cast<double>(arg1);
      double mzRangeEnd   = qscriptvalue_cast<double>(arg2);

      return thisMassSpectrum()->valSum(mzRangeStart, mzRangeEnd);
    }
  else
    ctx->throwError(
      "Syntax error: function tic() takes either 0 or 2 numbers as arguments.");

  return -1;
}


int
MassSpectrumJsPrototype::combine()
{
  // Depending on the argument(s) the combinations are different. We need to
  // scrutinize the arguments.

  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  if(argCount == 1)
    {

      // The single argument can be either DataPoint, Trace or MassSpectrum

      QScriptValue arg = ctx->argument(0);

      QVariant variant = arg.data().toVariant();

      if(!variant.isValid())
        {
          qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
                   << "Variant is not valid";

          ctx->throwError(
            "Syntax error: function combine takes one DataPoint object "
            ", one Trace or one MassSpectrum object or two numbers (mz & i) as "
            "argument.");

          return -1;
        }

      // Test if DataPoint

      if(variant.userType() == QMetaType::type("msXpSlibmass::DataPoint"))
        {
          DataPoint dp(qscriptvalue_cast<DataPoint>(arg));

          if(!dp.isValid())
            {
              ctx->throwError(
                "Syntax error: function combine takes one DataPoint object "
                ", one Trace or one MassSpectrum object or two numbers (mz & "
                "i) as argument.");

              return -1;
            }

          /*/js/
           * MassSpectrum.combine(dataPoint)
           *
           * Combine into this MassSpectrum object the <DataPoint> object
           *
           * dataPoint: <DataPoint> object to combine into this MassSpectrum
           *
           * Ex:
           *
           * var ms1 = new MassSpectrum;
           * ms1.initialize([123.321, 456.654, 789.987], [147.741,
           * 258.852,369.963]); ms1.asText(); // --> output is:
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           * ms1.tic(); // -> 776.556
           *
           * var dp1 = new DataPoint(123.321, 456.654);
           * ms1.combine(dp1);
           * ms1.asText(); // --> output is:
           *
           * 123.3210000000 604.3950000000 // value incremented
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           * dp1.key = 800;
           * dp1.val = 1000;
           * ms1.combine(dp1);
           * ms1.asText(); // --> output is:
           *
           * 123.3210000000 604.3950000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           * 800.0000000000 1000.0000000000 // creation of new data point
           */

          return thisMassSpectrum()->combine(dp);
        }

      // Test if Trace

      if(variant.userType() == QMetaType::type("msXpSlibmass::Trace"))
        {
          Trace trace(qscriptvalue_cast<Trace>(arg));

          /*/js/
           * MassSpectrum.combine(trace)
           *
           * Combine into this MassSpectrum object the <Trace> object
           *
           * trace: <Trace> object to combine into this MassSpectrum
           *
           * Ex:
           *
           * var ms1 = new MassSpectrum;
           * ms1.initialize([123.321, 456.654, 789.987], [147.741, 258.852,
           * 369.963]); ms1.asText(); //  --> output is:
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           * ms1.tic(); // --> 776.556
           * var t1 = new Trace;
           * t1.initialize([123.321,600.000,789.987],[147.741, 300.000,
           * 369.963]); t1.asText(); // --> output is:
           *
           * 123.3210000000 147.7410000000
           * 600.0000000000 300.0000000000
           * 789.9870000000 369.9630000000
           *
           * t1.valSum(); // --> 817.704
           * ms1.combine(t1);
           * ms1.asText(); // --> output is:
           *
           * 123.3210000000 295.4820000000
           * 456.6540000000 258.8520000000
           * 600.0000000000 300.0000000000
           * 789.9870000000 739.9260000000
           *
           * ms1.tic(); // --> 1594.26
           *
           */

          return thisMassSpectrum()->combine(trace);
        }

      // Test if MassSpectrum

      if(variant.userType() == QMetaType::type("msXpSlibmass::MassSpectrum"))
        {
          MassSpectrum ms(qscriptvalue_cast<MassSpectrum>(arg));

          /*/js/
           * MassSpectrum.combine(massSpectrum)
           *
           * Combine into this MassSpectrum object the <MassSpectrum> object
           *
           * massSpectrum: <MassSpectrum> object to combine into this
           * MassSpectrum
           *
           * Ex:
           *
           * var ms1 = new MassSpectrum;
           * ms1.initialize([123.321, 456.654, 789.987], [147.741, 258.852,
           * 369.963]);
           *
           * ms1.asText(); // --> output is:
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           *
           * ms1.tic(); // --> 776.556
           *
           * var ms2 = new MassSpectrum(ms1);
           * ms2.combine(1500, 1000);
           * ms2.asText(); // --> output is:
           *
           * 123.3210000000 147.7410000000
           * 456.6540000000 258.8520000000
           * 789.9870000000 369.9630000000
           * 1500.0000000000 1000.0000000000
           *
           * ms2.combine(ms1);
           * ms2.asText(); // --> output is:
           *
           * 123.3210000000 295.4820000000
           * 456.6540000000 517.7040000000
           * 789.9870000000 739.9260000000
           * 1500.0000000000 1000.0000000000
           *
           * ms2.tic(); // --> 2553.112
           */

          return thisMassSpectrum()->combine(ms);
        }
    }
  else if(argCount == 2)
    {
      QScriptValue arg1 = ctx->argument(0);
      QScriptValue arg2 = ctx->argument(1);

      if(!arg1.isNumber() || !arg2.isNumber())
        {
          ctx->throwError(
            "Syntax error: function combine takes one DataPoint object "
            ", one Trace or one MassSpectrum object or two numbers (mz & i) as "
            "argument.");

          return -1;
        }

      double mz = qscriptvalue_cast<double>(arg1);
      double i  = qscriptvalue_cast<double>(arg2);

      /*/js/
       * MassSpectrum.combine(mz, i)
       *
       * Combine into this MassSpectrum object a data point in the form of
       * two <Number> values, m/z and intensity
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum;
       * ms1.initialize([123.321, 456.654, 789.987], [147.741, 258.852,
       * 369.963]); ms1.asText(); // --> output is:
       *
       * 123.3210000000 147.7410000000
       * 456.6540000000 258.8520000000
       * 789.9870000000 369.9630000000
       *
       * ms1.tic(); // --> 776.556
       * var mz1 = 123.321;
       * var i1 = 300.000
       * ms1.combine(mz1, i1);
       * ms1.asText(); // --> output is:
       *
       * 123.3210000000 447.7410000000 // value incremented
       * 456.6540000000 258.8520000000
       * 789.9870000000 369.9630000000
       *
       * ms1.combine(800, 1000);
       * ms1.asText(); // --> output is:
       *
       * 123.3210000000 447.7410000000
       * 456.6540000000 258.8520000000
       * 789.9870000000 369.9630000000
       * 800.0000000000 1000.0000000000 // new data point created
       */

      return thisMassSpectrum()->combine(DataPoint(mz, i));
    }
  else
    ctx->throwError(
      "Syntax error: function combine takes one DataPoint object "
      ", one Trace or one MassSpectrum object or two numbers (mz & i) as "
      "argument.");

  return -1;
}


int
MassSpectrumJsPrototype::subtract()
{
  // Depending on the argument(s) the combinations are different. We need to
  // scrutinize the arguments.

  QScriptContext *ctx = context();
  int argCount        = ctx->argumentCount();

  if(argCount == 1)
    {

      // The single argument can be either DataPoint, Trace or MassSpectrum

      QScriptValue arg = ctx->argument(0);

      QVariant variant = arg.data().toVariant();

      if(!variant.isValid())
        {
          qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
                   << "Variant is not valid";

          ctx->throwError(
            "Syntax error: function subtract takes one DataPoint object "
            ", one Trace or one MassSpectrum object or two numbers (mz & i) as "
            "argument.");

          return -1;
        }

      // Test if DataPoint

      if(variant.userType() == QMetaType::type("msXpSlibmass::DataPoint"))
        {
          DataPoint dp(qscriptvalue_cast<DataPoint>(arg));

          if(!dp.isValid())
            {
              ctx->throwError(
                "Syntax error: function subtract takes one DataPoint object "
                ", one Trace or one MassSpectrum object or two numbers (mz & "
                "i) as argument.");

              return -1;
            }

          /*/js/
           * MassSpectrum.subtract(dataPoint)
           *
           * Subtract from this MassSpectrum object the <DataPoint> object
           *
           * dataPoint: <DataPoint> object to subtract from this MassSpectrum
           */

          return thisMassSpectrum()->subtract(dp);
        }

      // Test if Trace

      if(variant.userType() == QMetaType::type("msXpSlibmass::Trace"))
        {
          Trace trace(qscriptvalue_cast<Trace>(arg));

          /*/js/
           * MassSpectrum.subtract(trace)
           *
           * Subtract from this MassSpectrum object the <Trace> object
           *
           * trace: <Trace> object to subtract from this MassSpectrum
           */

          return thisMassSpectrum()->subtract(trace);
        }

      // Test if MassSpectrum

      if(variant.userType() == QMetaType::type("msXpSlibmass::MassSpectrum"))
        {
          MassSpectrum ms(qscriptvalue_cast<MassSpectrum>(arg));

          /*/js/
           * MassSpectrum.subtract(massSpectrum)
           *
           * Subtract from this MassSpectrum object the <MassSpectrum> object
           *
           * massSpectrum: <MassSpectrum> object to subtract from this
           * MassSpectrum
           *
           * Ex:
           *
           * var ms1 = new MassSpectrum;
           * ms1.initialize([123.321, 456.654, 789.987], [147.741, 258.852,
           * 369.963]); ms1.asText(); // --> output is: 123.3210000000
           * 147.7410000000 456.6540000000 258.8520000000 789.9870000000
           * 369.9630000000
           *
           * var ms2 = new MassSpectrum(ms1);
           * ms2.subtract(ms1);
           * ms2.asText(); // --> output is:
           *
           * 123.3210000000 0.0000000000
           * 456.6540000000 0.0000000000
           * 789.9870000000 0.0000000000
           */

          return thisMassSpectrum()->subtract(ms);
        }
    }
  else if(argCount == 2)
    {
      QScriptValue arg1 = ctx->argument(0);
      QScriptValue arg2 = ctx->argument(1);

      if(!arg1.isNumber() || !arg2.isNumber())
        {
          ctx->throwError(
            "Syntax error: function subtract takes one DataPoint object "
            ", one Trace or one MassSpectrum object or two numbers (mz & i) as "
            "argument.");

          return -1;
        }

      double mz = qscriptvalue_cast<double>(arg1);
      double i  = qscriptvalue_cast<double>(arg2);

      /*/js/
       * MassSpectrum.subtract(mz, i)
       *
       * Subtract from this MassSpectrum object a data point in the form of
       * two <Number> values, m/z and intensity
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum;
       * ms1.initialize([123.321, 456.654, 789.987], [147.741, 258.852,
       * 369.963]); ms1.asText(); // --> output is:
       *
       * 123.3210000000 147.7410000000
       * 456.6540000000 258.8520000000
       * 789.9870000000 369.9630000000
       *
       * ms1.subtract(123.321,100);
       * ms1.asText(); // --> output is:
       *
       * 123.3210000000 47.7410000000
       * 456.6540000000 258.8520000000
       * 789.9870000000 369.9630000000
       */

      return thisMassSpectrum()->subtract(DataPoint(mz, i));
    }
  else
    ctx->throwError(
      "Syntax error: function subtract takes one DataPoint object "
      ", one Trace or one MassSpectrum object or two numbers (mz & i) as "
      "argument.");

  return -1;
}


QScriptValue
MassSpectrumJsPrototype::valueOf() const
{
  return thisObject().data();
}


} // namespace msXpSlibmass
