/* 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 <QRegularExpressionMatch>
#include <QScriptEngine>
#include <QScriptString>
#include <QScriptClassPropertyIterator>


/////////////////////// Local includes
#include <globals/globals.hpp>

#include <libmass/MassSpectrum.hpp>
#include <libmass/DataPointJs.hpp>
#include <libmass/MassSpectrumJs.hpp>
#include <libmass/MassSpectrumJsPrototype.hpp>
#include <libmass/MassSpectrumJsPropertyIterator.hpp>


#include <stdlib.h>


Q_DECLARE_METATYPE(msXpSlibmass::MassSpectrumJs *);
Q_DECLARE_METATYPE(msXpSlibmass::DataPoint *);


namespace msXpSlibmass
{

/*/js/ Class: MassSpectrum
 * <comment>This class is the main class for handling mass spectra.
 * MassSpectrum objects can be "combination spectra", that is, they correspond
 * to the summation of a number of spectra. When a combination of mass spectra
 * is performed, the combination spectrum is created empty at first and is
 * then "configured" to receive the result of the sequential combination of
 * all the mass spectra that are to be summated. There are a number of member
 * data that are devoted to that combination configuration.
 *
 * A spectrum is actually a <Trace> that has a set of particular members:
 * - rt: the retention time at which the spectrum was acquired
 * - dt: the mobility drift time (for ion mobility spectra)
 * - binCount: the number of bins set up in a combination spectrum
 * - binSize: the size of the bins in the combination spectrum
 * - binSizeType: the type of the bin size (enum AMU, PPM, RES)
 * - binSizeTypestring: <String> representation of binSizeType
 * - minMz: the minimum m/z value of the combination specrum
 * - maxMz: the maximum m/z value of the combination specrum
 * - applyMzShift: tells if the m/z shift should be applied
 * - mzShift: m/z shift applied (or not) to each combined mass spectrum
 * - removeZeroValDataPoints: tells if the data points in the spectrum that
 *   have a m/z with 0 intensity should be removed</comment>
 */

MassSpectrumJs::MassSpectrumJs(QScriptEngine *engine)
  : QObject(engine), QScriptClass(engine)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  qScriptRegisterMetaType<MassSpectrum>(engine, toScriptValue, fromScriptValue);

  title       = engine->toStringHandle(QLatin1String("title"));
  length      = engine->toStringHandle(QLatin1String("length"));
  rt          = engine->toStringHandle(QLatin1String("rt"));
  dt          = engine->toStringHandle(QLatin1String("dt"));
  binCount    = engine->toStringHandle(QLatin1String("binCount"));
  binSize     = engine->toStringHandle(QLatin1String("binSize"));
  binSizeType = engine->toStringHandle(QLatin1String("binSizeType"));
  binSizeTypeString =
    engine->toStringHandle(QLatin1String("binSizeTypeString"));
  minMz        = engine->toStringHandle(QLatin1String("minMz"));
  maxMz        = engine->toStringHandle(QLatin1String("maxMz"));
  applyMzShift = engine->toStringHandle(QLatin1String("applyMzShift"));
  mzShift      = engine->toStringHandle(QLatin1String("mzShift"));
  removeZeroValDataPoints =
    engine->toStringHandle(QLatin1String("removeZeroValDataPoints"));

  proto = engine->newQObject(new MassSpectrumJsPrototype(this),
                             QScriptEngine::QtOwnership,
                             QScriptEngine::SkipMethodsInEnumeration |
                               QScriptEngine::ExcludeSuperClassMethods |
                               QScriptEngine::ExcludeSuperClassProperties);

  QScriptValue global = engine->globalObject();

  proto.setPrototype(global.property("Object").property("prototype"));

  ctor = engine->newFunction(construct, proto);
  ctor.setData(engine->toScriptValue(this));
}


MassSpectrumJs::~MassSpectrumJs()
{
}


QString
MassSpectrumJs::name() const
{
  return QLatin1String("MassSpectrum");
}


QScriptValue
MassSpectrumJs::prototype() const
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__;
  return proto;
}


QScriptValue
MassSpectrumJs::constructor()
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  return ctor;
}


/*/js/
 * MassSpectrum()
 *
 * Constructor of a MassSpectrum object
 *
 * Ex:
 *
 * var ms1 = new MassSpectrum();
 */
QScriptValue
MassSpectrumJs::newInstance()
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  MassSpectrum massSpectrum;

  return newInstance(massSpectrum);
}


/*/js/
 * MassSpectrum(title)
 *
 * Constructor of a MassSpectrum object
 *
 * title: <String> containing the title of the MassSpectrum object
 *
 * Ex:
 *
 * var ms1 = new MassSpectrum("spectrum title");
 * ms1.title; // --> spectrum title
 */
QScriptValue
MassSpectrumJs::newInstance(const QString &title)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  MassSpectrum massSpectrum(title);

  return newInstance(massSpectrum);
}


/*/js/
 * MassSpectrum(other)
 *
 * Constructor of a MassSpectrum object
 *
 * other: <Trace> object to be used to initialize this 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(t1);
 * ms1.asText();
 *
 * 123.3210000000 147.7410000000
 * 456.6540000000 258.8520000000
 * 789.9870000000 369.9630000000
 */
QScriptValue
MassSpectrumJs::newInstance(const Trace &other)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  // We need to first create a mass spectrum object initialized using other
  // so that the script object will actually be a MassSpectrum object and
  // not a Trace object.
  MassSpectrum massSpectrum(other);

  QScriptValue data = engine()->newVariant(QVariant::fromValue(massSpectrum));
  QVariant variant  = data.toVariant();
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
  //<< "Variant type:" << variant.userType() << "name:" << variant.typeName();

  // 'this', below, is because the JS object (data) needs to be linked to
  // the corresponding JS class that must match the class of the object.
  // 'data' is an object of MassSpectrum class and thus needs to be
  // associated to the MassSpectrumJs class (that is, this).

  qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
           << "Right before returning QScriptValue as newObject(this, data);";

  return engine()->newObject(this, data);
}


/*/js/
 * MassSpectrum(other)
 *
 * Constructor of a MassSpectrum object
 *
 * other: <MassSpectrum> object to be used to initialize this 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
 *
 * ms1.rt = 1.2;
 * ms1.dt = 0.00325698;
 *
 * var ms2 = new MassSpectrum(ms1);
 * ms2.asText();
 *
 * 123.3210000000 147.7410000000
 * 456.6540000000 258.8520000000
 * 789.9870000000 369.9630000000
 *
 * ms2.rt; // --> 1.2
 * ms2.dt; // --> 0.00325698
 */
QScriptValue
MassSpectrumJs::newInstance(const MassSpectrum &other)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  QScriptValue data = engine()->newVariant(QVariant::fromValue(other));

  // 'this', below, is because the JS object (data) needs to be linked to
  // the corresponding JS class that must match the class of the object.
  // 'data' is an object of MassSpectrum class and thus needs to be
  // associated to the MassSpectrumJs class (that is, this).

  qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
           << "Right before returning QScriptValue as newObject(this, data);";

  return engine()->newObject(this, data);
}


QScriptValue::PropertyFlags
MassSpectrumJs::propertyFlags(const QScriptValue & /*object*/,
                              const QScriptString &name,
                              uint /*id*/)
{
  // if (name == title)
  // return QScriptValue::Undeletable;

  return QScriptValue::Undeletable;
}


QScriptClass::QueryFlags
MassSpectrumJs::queryProperty(const QScriptValue &object,
                              const QScriptString &name,
                              QueryFlags flags,
                              uint *id)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
  //<< "with name:" << name;

  MassSpectrum *massSpectrum = qscriptvalue_cast<MassSpectrum *>(object.data());

  if(massSpectrum == Q_NULLPTR)
    {
      qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
               << "massSpectrum is Q_NULLPTR";

      return 0;
    }

  if(name == title)
    {
      return flags;
    }
  else if(name == length)
    {
      return flags;
    }
  else if(name == rt)
    {
      return flags;
    }
  else if(name == dt)
    {
      return flags;
    }
  else if(name == binCount)
    {
      return flags;
    }
  else if(name == binSize)
    {
      return flags;
    }
  else if(name == binSizeType)
    {
      return flags;
    }
  else if(name == binSizeTypeString)
    {
      return flags;
    }
  else if(name == minMz)
    {
      return flags;
    }
  else if(name == maxMz)
    {
      return flags;
    }
  else if(name == applyMzShift)
    {
      return flags;
    }
  else if(name == mzShift)
    {
      return flags;
    }
  else if(name == removeZeroValDataPoints)
    {
      return flags;
    }


  bool isArrayIndex;

  qint32 index = name.toArrayIndex(&isArrayIndex);

  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
  //"index is" << index << "and isArrayIndex is" << isArrayIndex;

  if(!isArrayIndex)
    {
      // It is essential to return 0 here, otherwise the prototype will never
      // get called.

      return 0;
    }

  *id = index;

  if((flags & HandlesReadAccess) && (index >= massSpectrum->size()))
    flags &= ~HandlesReadAccess;

  return flags;
}


QScriptValue
MassSpectrumJs::property(const QScriptValue &object,
                         const QScriptString &name,
                         uint id)
{
  MassSpectrum *massSpectrum = qscriptvalue_cast<MassSpectrum *>(object.data());

  if(!massSpectrum)
    {
      qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
               << "massSpectrum is Q_NULLPTR";

      return QScriptValue();
    }

  if(name == title)
    {
      /*/js/
       * MassSpectrum.title
       *
       * Return the title <String> property.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum("spectrum title");
       * ms1.title; // --> spectrum title
       */
      return QScriptValue(massSpectrum->m_title);
    }
  else if(name == length)
    {
      /*/js/
       * MassSpectrum.length
       *
       * Return the length <Number> property (number of <DataPoint> objects).
       *
       * 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
       *
       * ms1.length; // --> 3
       */
      return massSpectrum->size();
    }
  else if(name == rt)
    {
      /*/js/
       * MassSpectrum.rt
       *
       * Return the rt <Number> property (retention time at which this mass
       * spectrum was acquired.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       * ms1.rt = 1.2;
       *
       * ms1.rt; // --> 1.2
       */
      return massSpectrum->m_rt;
    }
  else if(name == dt)
    {
      /*/js/
       * MassSpectrum.dt
       *
       * Return the dt <Number> property (ion mobility drift time at which
       * this mass spectrum was acquired.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       * ms1.dt = 0.00325698;
       *
       * ms1.dt; // --> 0.00325698
       */
      return massSpectrum->m_dt;
    }
  else if(name == binCount)
    {
      /*/js/
       * MassSpectrum.binCount
       *
       * Return the bin count <Number> property (number of bins in this mass
       * spectrum).
       */
      return massSpectrum->m_binCount;
    }
  else if(name == binSize)
    {
      /*/js/
       * MassSpectrum.binSize
       *
       * Return the bin size <Number> property (size of the bins in this mass
       * spectrum).
       */
      return massSpectrum->m_binSize;
    }
  else if(name == binSizeType)
    {
      /*/js/
       * MassSpectrum.binSizeType
       *
       * Return the bin size type property as a <Number>.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       * ms1.binSizeType = 2;
       * ms1.binSizeType; // --> 2
       * ms1.binSizeTypeString = "RES";
       * ms1.binSizeType; // --> 4
       */

      return massSpectrum->m_binSizeType;
    }
  else if(name == binSizeTypeString)
    {
      /*/js/
       * MassSpectrum.binSizeTypeString
       *
       * Return the bin size type property as a <String>.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       * ms1.binSizeType = 2;
       * ms1.binSizeTypeString; // -> MZ;
       */

      return msXpS::massToleranceTypeMap.value(massSpectrum->m_binSizeType);
    }
  else if(name == minMz)
    {
      /*/js/
       * MassSpectrum.minMz
       *
       * Return the <Number> minimum m/z value to be used to craft the bins.
       */

      return massSpectrum->m_minMz;
    }
  else if(name == maxMz)
    {
      /*/js/
       * MassSpectrum.maxMz
       *
       * Return the <Number> maximum m/z value to be used to craft the bins.
       */

      return massSpectrum->m_maxMz;
    }
  else if(name == applyMzShift)
    {
      /*/js/
       * MassSpectrum.applyMzShift
       *
       * Return the <Boolean> value telling if the m/z shift should be
       * applied.
       */

      return massSpectrum->m_applyMzShift;
    }
  else if(name == mzShift)
    {
      /*/js/
       * MassSpectrum.mzShift
       *
       * Return the <Number> m/z shift value to apply when combining spectra.
       */
      return massSpectrum->m_mzShift;
    }
  else if(name == removeZeroValDataPoints)
    {

      /*/js/
       * MassSpectrum.removeZeroValDataPoints
       *
       * Return the <Boolean> value telling if the <DataPoint> objects having
       * m/z keys of a 0-intensity value should be removed from the spectrum.
       */
      return massSpectrum->m_removeZeroValDataPoints;
    }
  else
    {
      // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

      qint32 index = id;

      if((index < 0) || (index >= massSpectrum->size()))
        return QScriptValue();

      // qDebug() << __FILE__ << __LINE__ << __FUNCTION__
      //<< "The index is:" << index
      //<< "and the variant:" <<
      //QVariant::fromValue(*(massSpectrum->at(index)));

      QScriptValue data =
        engine()->newVariant(QVariant::fromValue(massSpectrum->at(index)));

      // MassPeak *massPeak = qscriptvalue_cast<MassPeak *>(data);
      // qDebug() << __FILE__ << __LINE__ << __FUNCTION__
      //<< "The mass peak:" << massPeak->mz() << "/" << massPeak->i();

      // We need to allocate the proper JS proxy for the object class: the
      // class of the native object is MassPeak, so we need to allocate a
      // MassPeakJs instance to feed to newObject() below. Only if we do this,
      // will we have a properly behaving MassPeak JS object when accessing
      // the individual members of the mass spectrum.

      /*/js/
       * MassSpectrum[index]
       *
       * Return the <DataPoint> object at index.
       *
       * 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 dp0 = ms1[0];
       * dp0.key; // --> 123.321
       * dp0.val; // --> 147.741
       *
       * ms1[0].key; // --> 123.321
       * ms1[0].val; // --> 147.741
       */

      DataPointJs *dataPointJs = new DataPointJs(engine());

      return engine()->newObject(dataPointJs, data);
    }

  return QScriptValue();
}


void
MassSpectrumJs::setProperty(QScriptValue &object,
                            const QScriptString &name,
                            uint id,
                            const QScriptValue &value)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  MassSpectrum *massSpectrum = qscriptvalue_cast<MassSpectrum *>(object.data());

  if(name == title)
    {
      /*js/
       * MassSpectrum.title = <String>
       *
       * Set the <String> property title.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.title = "spectrum title";
       *
       * ms1.title; // --> spectrum title
       */
      massSpectrum->m_title = qscriptvalue_cast<QString>(value);
    }
  else if(name == rt)
    {
      /*js/
       * MassSpectrum.rt = <Number>
       *
       * Set the <Number> property rt (retention time).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.rt = 1.333;
       *
       * ms1.rt; // --> 1.333
       */
      massSpectrum->m_rt = qscriptvalue_cast<double>(value);
    }
  else if(name == dt)
    {
      /*js/
       * MassSpectrum.dt = <Number>
       *
       * Set the <Number> property dt (drift time).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.dt = 21.333;
       *
       * ms1.dt; // --> 21.333
       */
      massSpectrum->m_dt = qscriptvalue_cast<double>(value);
    }
  else if(name == binCount)
    {
      /*js/
       * MassSpectrum.binCount = <Number>
       *
       * Set the <Number> property binCount (number of bins in the spectrum).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.binCount = 1333;
       *
       * ms1.binCount; // --> 1333
       */
      massSpectrum->m_binCount = qscriptvalue_cast<int>(value);
    }
  else if(name == binSize)
    {
      /*js/
       * MassSpectrum.binSize = <Number>
       *
       * Set the <Number> property binSize (size of the m/z bins in the
       * spectrum).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.binSize = 0.005;
       *
       * ms1.binSize; // --> 0.005
       */
      massSpectrum->m_binSize = qscriptvalue_cast<double>(value);
    }
  else if(name == binSizeType)
    {
      /*js/
       * MassSpectrum.binSizeType = <Number>
       *
       * Set the <Number> property binSizeType (type of the bin unit).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.binSizeType = 0;
       *
       * ms1.binSizeType; // --> 0
       */
      massSpectrum->m_binSizeType = qscriptvalue_cast<double>(value);
    }
  else if(name == binSizeTypeString)
    {
      /*js/
       * MassSpectrum.binSizeTypeString = <String>
       *
       * Set the <Number> property binSizeType (type of the bin unit) usin the
       * string representation.
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.binSizeTypeString = MZ;
       *
       * ms1.binSizeType; // --> 2
       * ms1.binSizeTypeString; // --> MZ
       */
      massSpectrum->m_binSizeType =
        msXpS::massToleranceTypeMap.key(qscriptvalue_cast<QString>(value));
    }
  else if(name == minMz)
    {
      /*js/
       * MassSpectrum.minMz = <Number>
       *
       * Set the <Number> property minMz (smallest m/z value of the spectrum).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.minMz = 500.000;
       *
       * ms1.minMz; // --> 500.000
       */
      massSpectrum->m_minMz = qscriptvalue_cast<double>(value);
    }
  else if(name == maxMz)
    {
      /*js/
       * MassSpectrum.maxMz = <Number>
       *
       * Set the <Number> property maxMz (greatest m/z value of the spectrum).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.maxMz = 1500.000;
       *
       * ms1.maxMz; // --> 1500.000
       */
      massSpectrum->m_maxMz = qscriptvalue_cast<double>(value);
    }
  else if(name == applyMzShift)
    {
      /*js/
       * MassSpectrum.applyMzShift = <Boolean>
       *
       * Set the <Boolean> property applyMzShift (tell if the m/z shift should
       * be applied).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.applyMzShift = false;
       *
       * ms1.applyMzShift; // --> false
       */
      massSpectrum->m_applyMzShift = qscriptvalue_cast<bool>(value);
    }
  else if(name == mzShift)
    {
      /*js/
       * MassSpectrum.mzShift = <Number>
       *
       * Set the <Number> property mzShift (m/z shift value to apply to the
       * spectra upon combination).
       *
       * Ex:
       *
       * var ms1 = new MassSpectrum();
       *
       * ms1.mzShift = 0.0022
       *
       * ms1.mzShift; // --> 0.0022
       */
      massSpectrum->m_mzShift = qscriptvalue_cast<double>(value);
    }

  // We do not handle setting DataPoint yet.

  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
  //<< "Right before returning void";
  return;
}


QScriptClassPropertyIterator *
MassSpectrumJs::newIterator(const QScriptValue &object)
{
  return new MassSpectrumJsPropertyIterator(object);
}


QScriptValue
MassSpectrumJs::construct(QScriptContext *ctx, QScriptEngine *)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()" ;

  MassSpectrumJs *cls =
    qscriptvalue_cast<MassSpectrumJs *>(ctx->callee().data());

  if(!cls)
    return QScriptValue();

  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
  //<< "Found the MassSpectrumJs class.";

  int argCount = ctx->argumentCount();

  if(argCount == 1)
    {
      QScriptValue arg = ctx->argument(0);

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

      if(variant.userType() == QMetaType::type("msXpSlibmass::MassSpectrum"))
        {
          // qDebug() << __FILE__ << __LINE__ << __FUNCTION__<< "()"
          //<< "The argument passed to the constructor is a MassSpectrum.";

          return cls->newInstance(qscriptvalue_cast<MassSpectrum>(arg));
        }
      else if(variant.userType() == QMetaType::type("msXpSlibmass::Trace"))
        {
          // qDebug() << __FILE__ << __LINE__ << __FUNCTION__<< "()"
          //<< "The argument passed to the constructor is a Trace.";

          return cls->newInstance(qscriptvalue_cast<Trace>(arg));
        }
      else if(arg.isString())
        {
          // The string is the title of the mass spectrum.
          return cls->newInstance(
            MassSpectrum(qscriptvalue_cast<QString>(arg)));
        }
    }

  // By default return an empty mass spectrum.
  return cls->newInstance();
}


QScriptValue
MassSpectrumJs::toScriptValue(QScriptEngine *eng,
                              const MassSpectrum &massSpectrum)
{
  QScriptValue ctor = eng->globalObject().property("MassSpectrum");

  MassSpectrumJs *cls = qscriptvalue_cast<MassSpectrumJs *>(ctor.data());

  if(!cls)
    return eng->newVariant(QVariant::fromValue(massSpectrum));

  return cls->newInstance(massSpectrum);
}


void
MassSpectrumJs::fromScriptValue(const QScriptValue &obj,
                                MassSpectrum &massSpectrum)
{
  massSpectrum = qvariant_cast<MassSpectrum>(obj.data().toVariant());
}


} // namespace msXpSlibmass
