/*
 * This file is part of OpenModelica.
 *
 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
 * c/o Linköpings universitet, Department of Computer and Information Science,
 * SE-58183 Linköping, Sweden.
 *
 * All rights reserved.
 *
 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
 *
 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
 * Public License (OSMC-PL) are obtained from OSMC, either from the above
 * address, from the URLs:
 * http://www.openmodelica.org or
 * https://github.com/OpenModelica/ or
 * http://www.ida.liu.se/projects/OpenModelica,
 * and in the OpenModelica distribution.
 *
 * GNU AGPL version 3 is obtained from:
 * https://www.gnu.org/licenses/licenses.html#GPL
 *
 * This program is distributed WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
 *
 * See the full OSMC Public License conditions for more details.
 *
 */

/*
 * @author Adeel Asghar <adeel.asghar@liu.se>
 */

#ifndef DOCUMENTATIONWIDGET_H
#define DOCUMENTATIONWIDGET_H

#include <QWidget>
#include <QToolButton>
#include <QTabBar>
#include <QFile>
#if defined(__EMSCRIPTEN__) || defined(OM_OMEDIT_NO_WEBENGINE)
#include "Modeling/qtwebengine_compat.h" // QtWebEngine unavailable on wasm / stubbed on MSVC
#elif QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QWebEngineView>
#include <QWebEnginePage>
#else // #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QWebView>
#endif // #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QToolBar>
#include <QComboBox>
#include <QFontComboBox>
#include <QSpinBox>
#include <QColorDialog>

class LibraryTreeItem;
class DocumentationHistory
{
public:
  LibraryTreeItem *mpLibraryTreeItem;
  QPoint mScrollPosition;
  DocumentationHistory(LibraryTreeItem *pLibraryTreeItem)
  {
    mpLibraryTreeItem = pLibraryTreeItem;
    mScrollPosition = QPoint(0, 0);
  }
  bool operator==(const DocumentationHistory &documentationHistory) const
  {
    return (documentationHistory.mpLibraryTreeItem == this->mpLibraryTreeItem);
  }
};

class DocumentationViewer;
class HTMLEditor;
class DocumentationWidget : public QWidget
{
  Q_OBJECT
public:
  enum EditType {
    None,
    Info,
    Revisions,
    InfoHeader
  };
  DocumentationWidget(QWidget *pParent = 0);
  ~DocumentationWidget();
  QAction* getPreviousAction() {return mpPreviousAction;}
  QAction* getNextAction() {return mpNextAction;}
  DocumentationViewer* getDocumentationViewer() {return mpDocumentationViewer;}
  void showDocumentation(LibraryTreeItem *pLibraryTreeItem);
  void execCommand(const QString &commandName);
  void execCommand(const QString &commandName, const QString &valueArgument);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  QVariant runJavaScript(const QString &javaScript);
#endif // #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  bool queryCommandState(const QString &commandName);
  QString queryCommandValue(const QString &commandName);
  void saveScrollPosition();
  bool isExecutingPreviousNextButtons() const {return mExecutingPreviousNextButtons;}
  void setExecutingPreviousNextButtons(bool executingPreviousNextButtons) {mExecutingPreviousNextButtons = executingPreviousNextButtons;}
  QPoint getScrollPosition() const {return mScrollPosition;}
  void setScrollPosition(const QPoint &scrollPosition) {mScrollPosition = scrollPosition;}
  bool isEditingDocumentation() const {return mEditType != EditType::None;}
  void updateDocumentationHistory(LibraryTreeItem *pLibraryTreeItem);
private:
  QFile mDocumentationFile;
  QAction *mpPreviousAction;
  QAction *mpNextAction;
  QAction *mpEditInfoAction;
  QAction *mpEditRevisionsAction;
  QAction *mpEditInfoHeaderAction;
  QAction *mpSaveAction;
  QAction *mpCancelAction;
  DocumentationViewer *mpDocumentationViewer;
  QFrame *mpDocumentationViewerFrame;
  QWidget *mpEditorsWidget;
  QTabBar *mpTabBar;
  QWidget *mpHTMLEditorWidget;
  QToolBar *mpEditorToolBar;
  DocumentationViewer *mpHTMLEditor;
  QFrame *mpHTMLEditorFrame;
  QComboBox *mpStyleComboBox;
  QFontComboBox *mpFontComboBox;
  QSpinBox *mpFontSizeSpinBox;
  QAction *mpBoldAction;
  QAction *mpItalicAction;
  QAction *mpUnderlineAction;
  QAction *mpStrikethroughAction;
  QAction *mpSubscriptAction;
  QAction *mpSuperscriptAction;
  QColor mTextColor;
  QColorDialog *mpTextColorDialog;
  QToolButton *mpTextColorToolButton;
  QColor mBackgroundColor;
  QColorDialog *mpBackgroundColorDialog;
  QToolButton *mpBackgroundColorToolButton;
  QToolButton *mpAlignLeftToolButton;
  QToolButton *mpAlignCenterToolButton;
  QToolButton *mpAlignRightToolButton;
  QToolButton *mpJustifyToolButton;
  QAction *mpDecreaseIndentAction;
  QAction *mpIncreaseIndentAction;
  QAction *mpBulletListAction;
  QAction *mpNumberedListAction;
  QAction *mpLinkAction;
  QAction *mpUnLinkAction;
  HTMLEditor *mpHTMLSourceEditor;
  EditType mEditType;
  QList<DocumentationHistory> *mpDocumentationHistoryList;
  int mDocumentationHistoryPos;
  bool mExecutingPreviousNextButtons;
  QPoint mScrollPosition;

  QPixmap createPixmapForToolButton(QColor color, QIcon icon);
  void updatePreviousNextButtons();
  void writeDocumentationFile(QString documentation);
  bool isLinkSelected();
  bool removeDocumentationHistory(LibraryTreeItem *pLibraryTreeItem);
  void updateHTMLSourceEditor();
public slots:
  void previousDocumentation();
  void nextDocumentation();
  void editInfoDocumentation();
  void editRevisionsDocumentation();
  void editInfoHeaderDocumentation();
  void saveDocumentation(LibraryTreeItem *pNextLibraryTreeItem = 0);
  void cancelDocumentation();
  void toggleEditor(int tabIndex);
  void updateActions();
  void updateActionsHelper();
  void formatBlock(int index);
  void fontName(QFont font);
  void fontSize(int size);
  void subscript();
  void superscript();
  void applyTextColor();
  void applyTextColor(QColor color);
  void applyBackgroundColor();
  void applyBackgroundColor(QColor color);
  void alignLeft();
  void alignCenter();
  void alignRight();
  void justify();
  void bulletList();
  void numberedList();
  void createLink();
  void removeLink();
};

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class DocumentationPage : public QWebEnginePage
{
  Q_OBJECT
private:
  QUrl mUrl;
public:
  DocumentationPage(QObject *parent = nullptr);
protected:
  virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override;
signals:
  void linkClicked(const QUrl &url);
private slots:
  void emitLinkClicked();
};

class DocumentationViewer : public QWebEngineView
#else // #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class DocumentationViewer : public QWebView
#endif // #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
{
  Q_OBJECT
private:
  DocumentationWidget *mpDocumentationWidget;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  DocumentationPage *mpDocumentationPage;
#endif // #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
public:
  DocumentationViewer(DocumentationWidget *pDocumentationWidget, bool isContentEditable = false);
  void setFocusInternal();
private:
  void createActions();
  void resetZoom();
public slots:
  void processLinkClick(QUrl url);
  void requestFinished();
  void processLinkHover(QString link);
  void processLinkHover(QString link, QString title, QString textContent);
  void showContextMenu(QPoint point);
  void pageLoaded(bool ok);
protected:
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  virtual QWebEngineView* createWindow(QWebEnginePage::WebWindowType type) override;
#else // #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  virtual QWebView* createWindow(QWebPage::WebWindowType type) override;
#endif // #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  virtual void keyPressEvent(QKeyEvent *event) override;
  virtual void wheelEvent(QWheelEvent *event) override;
  virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
  bool mIsContentEditable;
};

#endif // DOCUMENTATIONWIDGET_H
