/* 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
 */


#pragma once


////////////////////////////// Stdlib includes
#include <vector>

////////////////////////////// Qt includes
#include <QDebug>
#include <QtGlobal>
#include <QString>
#include <QList>
#include <QTextStream>
#include <QRegularExpression>


/////////////////////// pappsomspp includes


/////////////////////// Local includes
#include "MsXpS/libXpertMassCore/jsclassregistrar.h"
#include "MsXpS/export-import-config.h"
#include "MsXpS/libXpertMassCore/globals.hpp"

/*
Bitwise stuff (from StackOverflow)

It is sometimes worth using an enum to name the bits:

enum ThingFlags = {
ThingMask  = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}

Then use the names later on. I.e. write

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

to set, clear and test. This way you hide the magic numbers from the rest of
your code.
 */

namespace MsXpS
{
namespace libXpertMassCore
{

/*  BEGIN CLASS JS REFERENCE
 *  namespace: MsXpS::libXpertMassCore
 *  class name: Utils
 *
 * BEGIN DESCRIPTION
 * This class can be used in JS in two ways:
 * 1. By direct use of the 'utils' singleton
 *    and directly calling the invokable functions like so:
 *    utils.unspacify("this text has spaces")
 * 2. By instantiating an object like so:
 *    var the_utils = new Utils()
 *    and later calling the functions as methods of the
 *    object like so:
 *    the_utils.unspacify("this text has spaces")
 * END DESCRIPTION
 */

class DECLSPEC Utils: public QObject
{
  Q_OBJECT

  /*$ JS PROP REF Defines the string used for XML indentation formatting*/
  Q_PROPERTY(QString xmlIndentationToken MEMBER xmlIndentationToken)

  public:
  /*$ JS INVOK REF Creates a new instance of Utils */
  Q_INVOKABLE explicit Utils(QObject *parent = nullptr);

  virtual ~Utils();

  // This regexp extracts a formula from a larger action formula containing one
  // or more subformulas. For example it would extract from the
  // "+C12.1-H0.9Na2-N0.5" formula the following subformulas: +C12.1 and -H0.9
  // and Na2 and -N0.5. This regular expression should be used with the
  // globalMatch() feature of QRegularExpression.

  static QRegularExpression subFormulaRegExp;

  static QRegularExpression xyFormatMassDataRegExp;

  static QRegularExpression endOfLineRegExp;

  static QString xmlIndentationToken;

  static QString configSettingsFilePath;

  static void
  initializeConfigSettingsFilePath(const QString &config_settings_file_path);

  static void messageOutputFormat(QtMsgType type,
                                  const QMessageLogContext &context,
                                  const QString &msg);

  void configureDebugMessagesFormat();

  /*$ JS INVOK REF Given the list of double values sets a number of statistical
   * values*/
  Q_INVOKABLE static void doubleListStatistics(QList<double> list,
                                               double &sum,
                                               double &average,
                                               double &variance,
                                               double &std_dev,
                                               double &smallest_non_zero,
                                               double &smallest,
                                               double &greatest,
                                               double &median);

  static void doubleVectorStatistics(std::vector<double> &vector,
                                     double &sum,
                                     double &average,
                                     double &variance,
                                     double &std_dev,
                                     double &smallest_non_zero,
                                     double &smallest,
                                     double &greatest,
                                     double &median);

  /*$ JS INVOK REF Tells if two double values can be told apart with the
   * precision of the computer.*/
  Q_INVOKABLE static bool
  almostEqual(double value1, double value2, int decimalPlaces = 10);

  QTextStream &qStdOut();

  /*$ JS INVOK REF Remove any space anywhere in the text string.*/
  Q_INVOKABLE static QString unspacify(const QString &text);

  /*$ JS INVOK REF Returns the binary representation of the value.*/
  Q_INVOKABLE static QString binaryRepresentation(int value);

  Q_INVOKABLE static QString elideText(const QString &text,
                                       int charsLeft            = 4,
                                       int charsRight           = 4,
                                       const QString &delimitor = "...");

  Q_INVOKABLE static QString stanzify(const QString &text, int width);
  Q_INVOKABLE static QString stanzifyOld(const QString &text, int width);

  Q_INVOKABLE static QString stanzifyParagraphs(const QString &text, int width);

  Q_INVOKABLE static int countZeroDecimals(double value);

  /*$ JS INVOK REF Returns the mass delta corresponding to ppm of value.*/
  Q_INVOKABLE static double ppm(double value, double ppm);

  Q_INVOKABLE static double addPpm(double value, double ppm);

  Q_INVOKABLE static double removePpm(double value, double ppm);

  Q_INVOKABLE static double res(double value, double res);

  Q_INVOKABLE static double addRes(double value, double res);

  Q_INVOKABLE static double removeRes(double value, double res);

  template <typename T>
  static QString pointerAsString(T *ptr);

  template <typename T>
  static T *stringAsPointer(const QString &str);

  static int testDiffBetweenTwoTextFiles(const QString &file_path_1,
                                         const QString &file_path_2);

  Q_INVOKABLE static QString joinErrorList(const ErrorList &error_list,
                                           const QString &separator = "\n");

#ifdef Q_OS_LINUX
  static bool isProcessRunningInLinux(const QString &process_name);
#endif

#ifdef Q_OS_WIN
  static bool isProcessRunningInWindows(const QString &process_name);
#endif

  Q_INVOKABLE static bool isProgramRunning(const QString &program_name);

  static void registerJsConstructor(QJSEngine *engine);
};

/*  END CLASS JS REFERENCE
 *  namespace: MsXpS::libXpertMassCore
 *  class name: Utils
 */


} // namespace libXpertMassCore

MSXPS_REGISTER_JS_CLASS(MsXpS::libXpertMassCore, Utils)

} // namespace MsXpS
