/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright (C) 2009--2020 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


/////////////////////// Qt includes
#include <QMainWindow>
#include <QJSEngine>
#include <QJSValue>
#include <QTreeWidgetItem>
#include <QSettings>

#include <Qsci/qsciscintilla.h>


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


/////////////////////// libXpertMassCore includes
#include "MsXpS/libXpertMassCore/globals.hpp"


/////////////////////// libXpertMassGUI includes
#include "MsXpS/libXpertMassGui/JavaScriptingGuiUtils.hpp"
#include "MsXpS/libXpertMassGui/JavaScriptingEnvironment.hpp"


/////////////////////// Local includes
#include "MsXpS/export-import-config.h"

namespace Ui
{
class JavaScriptingWnd;
}

namespace MsXpS
{
namespace libXpertMassGui
{

enum HistoryLoggingType
{
  Never     = 0x0000,
  OnSuccess = 1 << 0,
  OnFailure = 1 << 1,
  Always    = OnSuccess | OnFailure
};

enum LogTextColor
{
  Comment,
  Success,
  Undefined,
  Failure,
  JsInput
};


class ScriptingObjectTreeWidgetItem;

class DECLSPEC JavaScriptingWnd: public QMainWindow
{
  Q_OBJECT

  public:
  enum LogDestination
  {
    ScriptInput,
    ScriptOutput,
    History
  };

  enum ObjectTreeWidgetColumn
  {
    Name = 0,
    Alias,
    Last
  };

  enum StackedJsRefWidgetPage
  {
    PappsoMSpp   = 0,
    XpertMass    = 1,
    XpertMassGui = 2,
  };

  // Construction/Destruction

  JavaScriptingWnd(const QString &application_name,
                   QMainWindow *parent = nullptr);
  ~JavaScriptingWnd();

  void writeSettings();
  void readSettings();

  void initialize();

  JavaScriptingEnvironment *getScriptingEnvironment();

  const QColor m_defaultColor = QColor("black");

  QColor m_successColor   = QColor("green");
  QColor m_undefinedColor = QColor("black");
  QColor m_failureColor   = QColor("red");
  QColor m_commentColor   = QColor("gray");

  QColor m_jsInputColor = QColor("black");

  QMap<int, QColor> m_logTextColorMap;

  QString m_commentPrefix = "\t";

  QWidget *mp_parentWnd = 0;
  QString m_inScriptFileName;
  QString m_outScriptFileName;

  QString m_history;

  bool wasSelecting        = false;
  int m_lastHistoryIndex   = -1;
  int m_historyAnchorIndex = -1;

  HistoryLoggingType m_historyLoggingType = HistoryLoggingType::Always;

  void setHistoryLoggingType(HistoryLoggingType type);
  HistoryLoggingType historyLoggingType() const;

  Q_INVOKABLE int restoreHistory(QSettings &settings);

  Q_INVOKABLE void resetHistory();
  Q_INVOKABLE void saveHistory();
  Q_INVOKABLE void showHistory();
  Q_INVOKABLE QString historyAsString(
    bool colorTagged = false, const QString &lineSeparator = QString("\n"));

  int restoreHistoryLoggingType(QSettings &settings);

  void initializeJsEngine(QJSEngine *js_engine_p);

  QColor logColor(LogTextColor contextColor = LogTextColor::Comment);

  void logOutTextEdit(const QString &text,
                      LogTextColor color = LogTextColor::Comment);

  void feedBackForExposedQObject(const QString &object_name,
                                 const QString &object_alias,
                                 const QString &object_description);

  // Set appendToList to false to avoid appending the text to m_historyList.
  // Do so only carefully, that is, typically when calling this function
  // initially set the history text items in the listwidget and textedit
  // from the settings.
  void logHistory(const QString &text,
                  LogTextColor color = LogTextColor::Comment);

  QString &prependColorTag(QString &text,
                           LogTextColor color = LogTextColor::Comment);
  bool removeColorTag(QString &text, LogTextColor &color);

  Q_INVOKABLE void runScript(const QString &script,
                             const QString &comment = QString());

  Q_INVOKABLE void loadScriptFile(const QString &fileName = QString());

  Q_INVOKABLE void show();
  Q_INVOKABLE void hide();

  int verbatimFilterJsReferenceText(const QString *input_text_p,
                                    QString *filtered_text_p);
  int regexFilterJsReferenceText(const QString *input_text_p,
                                 QString *filtered_text_p);

  public slots:

  // History list widget //////

  void historyListWidgetCurrentRowChanged(int row);
  void historyListWidgetItemActivated();

  void historyLoggingCheckBoxStateChanged();
  void historyRegExpLineEditReturnPressed();
  void jsRefTextSearchLineEditReturnPressed();

  void codeTextToCodeEditor(const QString code_text, bool overwrite);

  void scriptHasFinishedRunning(QJSValue value);

  signals:

  protected:
  QsciScintilla *mp_codeEditor = nullptr;

  QString m_applicationName;

  QString m_scriptText;
  QString m_scriptComment;

  JavaScriptingGuiUtils *mp_javaScriptingGuiUtils = nullptr;
  JavaScriptingEnvironment *mp_scriptingEnvironment;

  QMap<QString, QTreeWidgetItem *> m_mapJsPropNameTreeWidgetItem;

  QMenu *mp_fileMenu;
  QAction *mp_loadScriptFileAct;

  bool m_shouldHistoryLoadCancel = false;

  Ui::JavaScriptingWnd *mp_ui;


  /////////////////// JavaScript reference text handling ///////////////////
  /////////////////// JavaScript reference text handling ///////////////////

  // This map relates the name of the software piece and the JS reference
  // text that relates to it. For example "libpappsomspp" or "libXpertMass"
  // or "libXpertMassGui".
  QMap<QString /*JS ref text label*/, QString /*actual JS ref text*/>
    m_jsRefLabelRefTextMap;

  // This function sets the JS reference text for *this library's flibXpertMass
  // and libXpertMassGui.
  void registerKnownJsReferenceTexts();
  // Add a new label/js_ref_text pair to the map. Any previous pair by the
  // same key is lost.
  void registerJsReferenceText(const QString &label, const QString &text);

  // Creates a new tab, sets its label and sets the JS reference text
  // as found as value of the label key.
  void displayMappedJsRefTextToTab(const QString &label);
  // Iterates in the m_jsRefLabelRefTextMap and for each found pair,
  // creates a new tab, sets its label and sets the JS reference text.
  void displayAllMappedJsRefTextsToTabs();

  int regexFilterJsReferenceText(const QString &input_text,
                                 QString &filtered_text);
  int verbatimFilterJsReferenceText(const QString &input_text,
                                    QString &filtered_text);

  void closeEvent(QCloseEvent *event) override;
  void keyPressEvent(QKeyEvent *event) override;

  QStringList historyAsStringList(bool colorTagged = true);
};


} // namespace libXpertMassGui
} // namespace MsXpS
