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


#pragma once


/////////////////////// Qt includes
#include <QScriptEngine>
#include <QScriptValue>
#include <QTreeWidgetItem>
#include <QSettings>

///////////////////////////// Local includes
#include <globals/globals.hpp>
#include "ui_ScriptingWnd.h"

using namespace msXpS;

namespace msXpSmineXpert
{


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

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


class ScriptingObjectTreeWidgetItem;

QScriptValue print(QScriptContext *context, QScriptEngine *engine);
QScriptValue printToFile(QScriptContext *context, QScriptEngine *engine);

class ScriptingWnd : public QMainWindow
{
  Q_OBJECT

  friend class TicChromWnd;

  protected:
  Ui::ScriptingWnd m_ui;

  QString m_applicationName;

  void closeEvent(QCloseEvent *event);
  bool eventFilter(QObject *obj, QEvent *ev);
  bool handleKeyPressEvent(QKeyEvent *event);

  QMap<QString, QTreeWidgetItem *> m_mapJsPropNameTreeWidgetItem;

  QStringList historyAsStringList(bool colorTagged = true);

  void setJsReferenceText();

  QMenu *mp_fileMenu;
  QAction *mp_runScriptFileAct;

  QString m_jsReferenceText;

  public:
  QScriptEngine m_scriptEngine;

  enum LogDestination
  {
    ScriptInput,
    ScriptOutput,
    History
  };
  enum ObjectTreeWidgetColumn
  {
    Name = 0,
    Alias,
    Last
  };

  // Construction/Destruction

  explicit ScriptingWnd(QWidget *parent, const QString &applicationName);
  ~ScriptingWnd();

  void writeSettings();
  void readSettings();

  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);

  bool publishQObject(
    QObject *object,
    QObject *parent,
    const QString &jsName,
    const QString &alias,
    const QString &comment,
    const QString &help,
    QScriptValue &jsValue,
    QScriptEngine::ValueOwnership ownership = QScriptEngine::QtOwnership,
    const QScriptEngine::QObjectWrapOptions &options =
      QScriptEngine::QObjectWrapOptions());

  bool publishEntityWithScript(QString script,
                               QObject *parent,
                               const QString &jsName,
                               const QString &alias,
                               const QString &comment,
                               const QString &help,
                               ScriptEntityType variableType,
                               QString *result);

  bool publishEntityWithScriptValue(QScriptValue scriptValue,
                                    QObject *parent,
                                    const QString &jsName,
                                    const QString &alias,
                                    const QString &comment,
                                    const QString &help,
                                    ScriptEntityType variableType,
                                    QString *result);

  ScriptingObjectTreeWidgetItem *
  getObjectTreeWidgetItemByQObject(QObject *parent);

  QList<ScriptingObjectTreeWidgetItem *>
  getObjectTreeWidgetItemsByColumnContent(const QString &text,
                                          ScriptingObjectTreeWidgetItem *parent,
                                          ObjectTreeWidgetColumn column);

  void deleteObjectTreeWidgetItemsByColumnContent(
    const QString &text,
    ScriptingObjectTreeWidgetItem *parent,
    ObjectTreeWidgetColumn column);

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

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

  // 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);

  void inputInTextEdit(const QString &text, bool overwrite = true);

  Q_INVOKABLE bool runScript(const QString &script,
                             const QString &comment = QString(),
                             QString *result        = Q_NULLPTR);

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

  public slots:

  // History list widget //////

  void historyListWidgetCurrentRowChanged(int row);
  void historyListWidgetItemActivated();
  void inTextEditTextChanged();
  void historyListWidgetSendTextToInTextEdit(const QString &scriptContents,
                                             bool overwrite);

  void objectTreeWidgetItemDoubleClicked(QTreeWidgetItem *item, int column);

  void historyLoggingCheckBoxStateChanged(int checkState);
  void historyRegExpLineEditReturnPressed();
  void jsRefTextRegExpLineEditReturnPressed();

  void publishedQObjectDestroyed(QObject *object = Q_NULLPTR);

  Q_INVOKABLE void runScriptFile(const QString &fileName = QString());
};


} // namespace msXpSmineXpert
