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


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

#include <minexpert/nongui/MzIntegrationParamsJs.hpp>
#include <minexpert/nongui/MzIntegrationParamsJsPrototype.hpp>
#include <minexpert/nongui/SavGolFilterJs.hpp>


#include <stdlib.h>


Q_DECLARE_METATYPE(msXpSmineXpert::MzIntegrationParamsJs *);


namespace msXpSmineXpert
{


/*/js/ Class: MzIntegrationParams
 * <comment>The MzIntegrationParams class provides an interface to all the
 * parameters that are required to configure all the integrations of mass
 * spectral data that combine into a MassSpectrum object.
 *
 * When combining multiple mass spectra into a single one, the process might
 * involve the creation of bins according to specific parameters measured on
 * the whole set of the spectra to be combined into the combination spectrum.
 * These parameters are configured using a MzIntegrationParams object. Its
 * members are:
 *
 * -binningType: <Number> type of the binning. The type of binning specifies
 *  if binning is arbitrary or data-based (refer to msXpS::BinningType for
 *  details). It might also specify that no binning is required.
 *
 * -binSize: <Number> size of the bins. A typical bin size would be 0.005 for
 *  a high resolution mass spectrometer with unit m/z.
 *
 * -binSizeType: <Number> type of the bin size. The bin size type specifies if
 *  the binSize value is to be considered a m/z value or a atomic mass unit
 *  value or a resolution value or a part-per-million value (refer to
 *  msXpS::MassToleranceType for details)
 *
 * -binSizeTypeString: <String> type of the bin size. This member datum hold a
 *  textual representation of the binSizeType member datum, like "PPM" or
 *  "RES" or "AMU" or "MZ".
 *
 * -applyMzShift: <Boolean> value that tells if the m/z shift correction
 *  should be applied.
 *
 * -removeZeroValDataPoints: <Boolean> that tells if the 0-val m/z data points
 *  should be removed from the combination spectrum once all the source mass
 *  spectra have been effectively combined into the combination spectrum.
 *
 * - applySavGolFilter: <Boolean> that tells if a Savitzky-Golay filtering is
 *   to be applied to the combination spectrum after all the source mass
 *   spectra have been combined to the combination spectrum.
 *
 * - savGolParams: <SavGolParams> object holding the configuration of a
 *   Savitzky-Golay filtering process.</comment>
 */


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

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

  binningType = engine->toStringHandle(QLatin1String("binningType"));
  binningTypeString =
    engine->toStringHandle(QLatin1String("binningTypeString"));
  binSize     = engine->toStringHandle(QLatin1String("binSize"));
  binSizeType = engine->toStringHandle(QLatin1String("binSizeType"));
  binSizeTypeString =
    engine->toStringHandle(QLatin1String("binSizeTypeString"));
  applyMzShift = engine->toStringHandle(QLatin1String("applyMzShift"));
  removeZeroValDataPoints =
    engine->toStringHandle(QLatin1String("removeZeroValDataPoints"));
  applySavGolFilter =
    engine->toStringHandle(QLatin1String("applySavGolFilter"));
  savGolParams = engine->toStringHandle(QLatin1String("savGolParams"));


  proto = engine->newQObject(new MzIntegrationParamsJsPrototype(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));
}


MzIntegrationParamsJs::~MzIntegrationParamsJs()
{
}


QString
MzIntegrationParamsJs::name() const
{
  return QLatin1String("MzIntegrationParams");
}


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


QScriptValue
MzIntegrationParamsJs::constructor()
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";
  return ctor;
}

/*/js/
 * MzIntegrationParams()
 *
 * Construct a MzIntegrationParams instance with default values.
 *
 * Ex:
 *
 * var mzip1 = new MzIntegrationParams();
 *
 * mzip1.binningType; // --> 0
 * mzip1.binningTypeString; // --> NONE
 */
QScriptValue
MzIntegrationParamsJs::newInstance()
{
  MzIntegrationParams mziParams;

  return newInstance(mziParams);
}


/*/js/
 * MzIntegrationParams(binningType, binSize, binSizeType,
 * applyMzShift, removeZeroValDataPoints)
 *
 * Construct a MzIntegrationParams instance using specified values.
 *
 * binningType: <Number> type of the binning (refer to msXpS::BinningType for
 * details) binSize: <Number> size of the bins binSizeType: <Number> type of the
 * bin size (refer to msXpS::MassToleranceType for details) applyMzShift:
 * <Boolean> tells if the m/z shift correction should be applied
 * removeZeroValDataPoints: <Boolean> tells if the 0-val m/z data points should
 * be removed
 *
 * Ex:
 *
 * var mzip1 = new MzIntegrationParams(1, 0.0055, 2, false, true);
 *
 * mzip1.binningTypeString; // --> DATA_BASED
 * mzip1.binSize; // --> 0.0055
 * mzip1.binSizeType; // --> 2
 * mzip1.binSizeTypeString; // --> MZ
 * mzip1.applyMzShift; // --> false
 * mzip1.removeZeroValDataPoints; // --> true
 */
QScriptValue
MzIntegrationParamsJs::newInstance(msXpS::BinningType binningType,
                                   double binSize,
                                   msXpS::MassToleranceType binSizeType,
                                   bool applyMzShift,
                                   bool removeZeroValDataPoints)
{
  MzIntegrationParams mziParams(
    binningType, binSize, binSizeType, applyMzShift, removeZeroValDataPoints);

  return newInstance(mziParams);
}


/*/js/
 *	MzIntegrationParams(mzIntegrationParams)
 *
 * Construct a MzIntegrationParams object using a <MzIntegrationParams>
 * template object.
 *
 * Ex:
 *
 * var mzip1 = new MzIntegrationParams(1, 0.0055, 2, false, true);
 *
 * mzip1.binningTypeString; // --> DATA_BASED
 * mzip1.binSize; // --> 0.0055
 * mzip1.binSizeType; // --> 2
 * mzip1.binSizeTypeString; // --> MZ
 * mzip1.applyMzShift; // --> false
 * mzip1.removeZeroValDataPoints; // --> true
 *
 * var mzip2 = new MzIntegrationParams(mzip1);
 *
 * mzip2.binningTypeString; // --> DATA_BASED
 * mzip2.binSize; // --> 0.0055
 * mzip2.binSizeType; // --> 2
 * mzip2.binSizeTypeString; // --> MZ
 * mzip2.applyMzShift; // --> false
 * mzip2.removeZeroValDataPoints; // --> true
 *
 * mzIntegrationParams: <MzIntegrationParams> to be used to initialize this
 *object
 */
QScriptValue
MzIntegrationParamsJs::newInstance(const MzIntegrationParams &other)
{
  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 MzIntegrationParam class and thus needs to be
  // associated to the MzIntegrationParamsJs class (that is, this).

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

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


/*/js/
 * MzIntegrationParams(savGolParams)
 *
 * Construct a MzIntegrationParams object using a SavGolParams template
 * object.
 *
 * Ex:
 *
 * var sgp1 = new SavGolParams(10, 10, 6, 0, true);
 * var mzip1 = new MzIntegrationParams(sgp1);
 *
 * mzip1.savGolParams.nL; // --> 10
 * mzip1.savGolParams.nR; // --> 10
 * mzip1.savGolParams.m; // --> 6
 * mzip1.savGolParams.lD; // --> 0
 *
 * savGolParams: <SavGolParams> object to be used to initialize this object's
 * SavGolParams
 */
QScriptValue
MzIntegrationParamsJs::newInstance(const SavGolParams &other)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  MzIntegrationParams mziParams(other);

  return newInstance(mziParams);
}


QScriptValue::PropertyFlags
MzIntegrationParamsJs::propertyFlags(const QScriptValue & /*object*/,
                                     const QScriptString &name,
                                     uint /*id*/)
{
  return QScriptValue::Undeletable;
}


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

  MzIntegrationParams *mziParams =
    qscriptvalue_cast<MzIntegrationParams *>(object.data());

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

      return 0;
    }

  if(name == binningType)
    {
      return flags;
    }
  if(name == binningTypeString)
    {
      return flags;
    }
  else if(name == binSize)
    {
      return flags;
    }
  else if(name == binSizeType)
    {
      return flags;
    }
  else if(name == binSizeTypeString)
    {
      return flags;
    }
  else if(name == applyMzShift)
    {
      return flags;
    }
  else if(name == removeZeroValDataPoints)
    {
      return flags;
    }
  else if(name == applySavGolFilter)
    {
      return flags;
    }
  else if(name == savGolParams)
    {
      return flags;
    }

  // It is essential to return 0 here, otherwise the prototype will never
  // get called.
  flags &= ~HandlesReadAccess;
  return flags;
}


QScriptValue
MzIntegrationParamsJs::property(const QScriptValue &object,
                                const QScriptString &name,
                                uint id)
{
  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()";

  MzIntegrationParams *mziParams =
    qscriptvalue_cast<MzIntegrationParams *>(object.data());

  if(!mziParams)
    return QScriptValue();

  if(name == binningType)
    {
      /*/js/
       * <MzintegrationParams>.binningType
       *
       * Return the binningType property of the object as a <Number>
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binningType; // --> 0
       *
       * Return the binning type property as a <Number>.
       */

      return QScriptValue(mziParams->m_binningType);
    }
  else if(name == binningTypeString)
    {
      /*/js/
       * <MzintegrationParams>.binningTypeString
       *
       * Return the binningType property of the object as a <String>
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binningTypeString; // --> NONE
       *
       * Return the binning type property as a <String>.
       */

      QString binningTypeString =
        msXpS::binningTypeMap.value(mziParams->m_binningType);
      qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
               << "string:" << binningTypeString;

      return msXpS::binningTypeMap.value(mziParams->m_binningType);
    }
  else if(name == binSize)
    {
      /*/js/
       * <MzIntegrationParams>.binSize
       *
       * Return the bin size property of the object.
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binSize; // --> NaN (uninitialized value)
       *
       * Return the bin size <Number> property (size of the bins in the mass
       * spectrum).
       */
      return QScriptValue(mziParams->m_binSize);
    }
  else if(name == binSizeType)
    {
      /*/js/
       * <MzintegrationParams>.binSizeType
       *
       * Return the binSizeType property of the object as a <Number>
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binSizeType; // --> 0
       *
       * Return the bin size type property as a <Number>.
       */

      return QScriptValue(mziParams->m_binSizeType);
    }
  else if(name == binSizeTypeString)
    {
      /*/js/
       * <MzintegrationParams>.binSizeTypeString
       *
       * Return the binSizeType property of the object as a <String>
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binSizeTypeString; // --> NONE
       *
       * Return the bin size type property as a <String>.
       */

      return msXpS::massToleranceTypeMap.value(mziParams->m_binSizeType);
    }
  else if(name == applyMzShift)
    {
      /*/js/
       * <MzIntegrationParams>.applyMzShift
       *
       * Ex:
       *
       *  var mzip1 = new MzIntegrationParams();
       *
       *  mzip1.applyMzShift; // --> false
       *  mzip1.applyMzShift = true;
       *  mzip1.applyMzShift; // --> true
       *
       * Return the <Boolean> value telling if the m/z shift should be
       * applied.
       */

      return QScriptValue(mziParams->m_applyMzShift);
    }
  else if(name == removeZeroValDataPoints)
    {
      /*/js/
       * <MzIntegrationParams>.removeZeroValDataPoints
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.applyMzShift; // --> false
       *
       * Return the <Boolean> value telling if the <DataPoint> objects having
       * m/z keys of a 0-intensity value should be removed from the
       * <MassSpectrum> object.
       */
      return QScriptValue(mziParams->m_removeZeroValDataPoints);
    }
  else if(name == applySavGolFilter)
    {
      /*/js/
       * <MzIntegrationParams>.applySavGolFilter
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.applySavGolFilter // --> false
       *
       * Return the <Boolean> value telling if the Savitzky-Golay filter
       * should be applied to the <MassSpectrum> object.
       */
      return QScriptValue(mziParams->m_applySavGolFilter);
    }
  else if(name == savGolParams)
    {

      /*/js/
       * <MzIntegrationParams>.savGolParams
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * var sgp1 = mzip1.savGolParams;
       *
       * sgp1.nL; // --> 15
       * sgp1.nR; // --> 15
       * sgp1.m; // --> 4
       * sgp1.lD; // --> 0
       * sgp1.convolveWithNr;	 // --> false
       *
       * Return the <SavGolParams> object from this <MzIntegrationParams>
       * object.
       */
      return SavGolFilterJs::toScriptValue(engine(), mziParams->m_savGolParams);
    }

  return QScriptValue();
}


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

  MzIntegrationParams *mziParams =
    qscriptvalue_cast<MzIntegrationParams *>(object.data());

  if(name == binningType)
    {
      /*js/
       * MzIntegrations.binningType = <Number>
       *
       * Set the binning type as a <Number>.
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binningType; // --> 0
       * mzip1.binningType = 2;
       * mzip1.binningType; // --> 2
       */

      mziParams->m_binningType =
        static_cast<msXpS::BinningType>(qscriptvalue_cast<int>(value));
    }
  else if(name == binningTypeString)
    {
      /*js/
       * MzIntegrations.binningTypeString = <Number>
       *
       * Set the binning type as a <String>.
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binningTypeString = "ARBITRARY";
       * mzip1.binningTypeString; // --> ARBITRARY
       * mzip1.binningType; // --> 2
       */

      int binningType =
        msXpS::binningTypeMap.key(qscriptvalue_cast<QString>(value));
      mziParams->m_binningType = static_cast<msXpS::BinningType>(binningType);
    }
  else if(name == binSize)
    {
      /*/js/
       * MzIntegrationParams.binSize = <Number>
       *
       * Set the bin size.
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       * mzip1.binSize; // --> NaN (uninitialized)
       * mzip1.binSize = 0.0055;
       * mzip1.binSize; // --> 0.0055
       */

      mziParams->m_binSize = qscriptvalue_cast<double>(value);
    }
  else if(name == binSizeType)
    {
      /*/js/
       * MzIntegrationParams.binSizeType = <Number>
       *
       * Set the bin size type as a <Number>
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.binSizeType; // --> 0
       * mzip1.binSizeTypeString; // --> NONE
       * mzip1.binSizeType=1;
       * mzip1.binSizeType; // --> 1
       * mzip1.binSizeTypeString; // --> PPM
       */
      mziParams->m_binSizeType =
        static_cast<msXpS::MassToleranceType>(qscriptvalue_cast<int>(value));
    }
  else if(name == binSizeTypeString)
    {
      /*/js/
       * MzIntegrationParams.binSizeTypeString = <String>
       *
       * Set the bin size type as a <String>
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       * mzip1.binSizeTypeString; // --> NONE
       * mzip1.binSizeTypeString = "RES";
       * mzip1.binSizeTypeString; // --> RES
       * mzip1.binSizeType; // --> 4
       */
      int binSizeType =
        msXpS::massToleranceTypeMap.key(qscriptvalue_cast<QString>(value));
      mziParams->m_binSizeType =
        static_cast<msXpS::MassToleranceType>(binSizeType);
    }
  else if(name == applyMzShift)
    {
      /*/js/
       * MzIntegrationParams.applyMzShift = <Boolean>
       *
       * Tell if the m/z shift between spectra must be applied
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.applyMzShift; // --> false
       * mzip1.applyMzShift = true;
       * mzip1.applyMzShift; // --> true
       */
      mziParams->m_applyMzShift = qscriptvalue_cast<bool>(value);
    }
  else if(name == removeZeroValDataPoints)
    {
      /*/js/
       * MzIntegrationParams.removeZeroValDataPoints = <Boolean>
       *
       * Tell if the DataPoint objects having a value of 0 need to be removed
       * from the spectrum.
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.applyMzShift; // --> false
       * mzip1.applyMzShift = true;
       * mzip1.applyMzShift; // --> true
       */

      mziParams->m_removeZeroValDataPoints = qscriptvalue_cast<bool>(value);
    }
  else if(name == applySavGolFilter)
    {
      /*/js/
       * MzIntegrationParams.removeZeroValDataPoints = <Boolean>
       *
       * Tell if the Savitzky-Golay filter needs to be applied to the
       * combination spectrum.
       *
       * Ex:
       *
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.applySavGolFilter; // --> false
       * mzip1.applySavGolFilter = true;
       * mzip1.applySavGolFilter; // --> true;
       */
      mziParams->m_applySavGolFilter = qscriptvalue_cast<bool>(value);
    }
  else if(name == savGolParams)
    {
      /*/js/
       * MzIntegrationParams.savGolParams = <SavGolParams>
       *
       * Initialize the member <SavGolParams> object using the parameter as
       * template.
       *
       * Ex:
       *
       * var sgp1 = new SavGolParams(10, 10, 6, 0, true);
       * var mzip1 = new MzIntegrationParams();
       *
       * mzip1.savGolParams.nL; // --> 15
       * mzip1.savGolParams.nR; // --> 15
       * mzip1.savGolParams = sgp1;
       * mzip1.savGolParams.nL; // --> 10
       * mzip1.savGolParams.nR; // --> 10
       */
      mziParams->m_savGolParams = qscriptvalue_cast<SavGolParams>(value);
    }

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


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

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

  if(!cls)
    return QScriptValue();

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

  int argCount = ctx->argumentCount();

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

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

      if(variant.isValid())
        {
          // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
          //<< "Variant user type:" << variant.userType();

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

              return cls->newInstance(
                qscriptvalue_cast<MzIntegrationParams>(arg));
            }
        }
      else
        {
          // Let's try to see if the parameter is a SavGolParams structure.
          variant = arg.toVariant();

          if(!variant.isValid())
            {
              qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
                       << "Variant is not valid, returning default-constructed "
                          "object.";

              return cls->newInstance();
            }

          // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
          //<< "QVariant user type: " << variant.userType();

          QScriptValue nLValue = arg.property("nL", QScriptValue::ResolveLocal);

          if(nLValue.isValid())
            {

              // Finally, we can take the constructor parameter as a
              // SavGolParams argument.
              SavGolParams params = qscriptvalue_cast<SavGolParams>(arg);

              // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
              //<< "We are constructing from SavGolParams.";

              return cls->newInstance(params);
            }
        }
    }
  else if(argCount == 5)
    {
      // We are constructing from raw values.

      QScriptValue binningTypeJSValue             = ctx->argument(0);
      QScriptValue binSizeJSValue                 = ctx->argument(1);
      QScriptValue binSizeTypeJSValue             = ctx->argument(2);
      QScriptValue applyMzShiftJSValue            = ctx->argument(3);
      QScriptValue removeZeroValDataPointsJSValue = ctx->argument(4);

      return cls->newInstance(
        static_cast<msXpS::BinningType>(binningTypeJSValue.toNumber()),
        binSizeJSValue.toNumber(),
        static_cast<msXpS::MassToleranceType>(binSizeTypeJSValue.toNumber()),
        applyMzShiftJSValue.toBoolean(),
        removeZeroValDataPointsJSValue.toBoolean());
    }

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


QScriptValue
MzIntegrationParamsJs::toScriptValue(QScriptEngine *eng,
                                     const MzIntegrationParams &mziParams)
{
  QScriptValue ctor = eng->globalObject().property("MzIntegrationParams");

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

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

  return cls->newInstance(mziParams);
}


void
MzIntegrationParamsJs::fromScriptValue(const QScriptValue &obj,
                                       MzIntegrationParams &mziParams)
{
  mziParams = qvariant_cast<MzIntegrationParams>(obj.data().toVariant());
}


} // namespace msXpSmineXpert
