//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================

#ifndef smtk_simulation_ace3p_qt_qtProgressDialog
#define smtk_simulation_ace3p_qt_qtProgressDialog

#include <QDialog>
#include <QMutex>
#include <QPixmap>
#include <QTime>
#include <QTimer>

#include "smtk/simulation/ace3p/qt/Exports.h"

namespace Ui
{
class qtProgressDialog;
}

/**
 * \brief Progress Dialog with more features than the standard QProgressDialog.
 * \details Progress Dialog with more features than the standard QProgressDialog, including:
 *            1) ability to output update messages
 *            2) auto-close feature upon completion (with or without a countdown delay)
 *            3) imposing a minimum duration before auto-close to prevent "strobing" dialog on and
 *                    rapidly off
 */
class SMTKACE3PQTEXT_EXPORT qtProgressDialog : public QDialog
{
  Q_OBJECT

signals:
  /** \brief Signal emitted when the 'Close' button is clicked - for connecting to external slots. */
  void closeClicked();
  /** \brief Signal emitted when the 'Cancel' button is clicked - for connecting to external slots. */
  void cancelClicked();

public:
  enum MessageType
  {
    Info,
    Warning,
    Error
  };

public slots:
  /** \brief Set the progress bar value. */
  void setValue(int progressValue);
  /** \brief Set the progress bar range of values. */
  void setRange(int minProgress, int maxProgress);
  /** \brief Set the progress bar minimum value. */
  void setMinimum(int minProgress);
  /** \brief Set the progress bar maximum value. */
  void setMaximum(int maxProgress);

  /** \brief Set whether the Cancel button is visible or hidden. */
  void setCancelButtonVisible(bool bVisible);
  /** \brief Set whether to automatically disable the Cancel button upon progress bar completion. */
  void setAutoDisableCancelButton(bool bAutoDisable);
  /** \brief Set whether the progress dialog automatically closes upon last progress bar tick. */
  void setAutoClose(bool bAutoClose);
  /** \brief Set a minimum duration that the progress dialog is visible. If run time is less than
   *         this duration, the difference is added as an Auto-close Delay. */
  void setMinDuration(uint seconds);
  /** \brief Delays the Auto-close of the progress dialog after the last progress bar tick by this
   *         number of seconds. */
  void setAutoCloseDelay(uint delay);
  /** \brief Controls the visibility of the Progress Message Box, and associated filter buttons. */
  void setMessageBoxVisible(bool bBoxVisible, bool bFiltersVisible);
  /** \brief Controls whether long messages in the Progress Message Box line wrap. */
  void setMessageBoxWordWrap(bool bWrap);
  /** \brief Controls whether icons are shown to the left of progress messages. */
  void setShowMessageIcons(bool bShow);
  /** \brief Manually triggers the Minimum Duration and Auto-close mechanisms in indeterminate use
   *         cases (cases with an unknown progress range). */
  void progressFinished();

  /** \brief Clear contents of the Progress Message Box. */
  void clearProgressMessages();
  /** \brief Add an information message to the Progress Message Box. */
  void setInfoText(QString progressMessage);
  /** \brief Add a warning message to the Progress Message Box. */
  void setWarningText(QString progressMessage);
  /** \brief Add an error message to the Progress Message Box. */
  void setErrorText(QString progressMessage);
  /** \brief Add a message to the Progress Message Box. Can be either information, or a
   *         warning/error. */
  void setProgressText(QString progressMessage = "", MessageType messageType = Info);
  /** \brief Combined function to set the progree bar value, and add a progress message. */
  void
  setProgress(uint progressValue, QString progressMessage = "", MessageType messageType = Info);

public:
  explicit qtProgressDialog(QWidget* parent = nullptr);
  explicit qtProgressDialog(
    QWidget* parent,
    uint minProgress,
    uint maxProgress,
    QString windowTitle = "");
  ~qtProgressDialog();

  /** \brief Set the progress bar label (this is not the window title). */
  void setLabelText(QString text);

private slots:
  void on_pushButton_Close_clicked();
  void on_pushButton_Cancel_clicked();
  void on_pushButton_Info_clicked();
  void on_pushButton_Warnings_clicked();
  void on_pushButton_Errors_clicked();

  void processAutoCloseTimer();
  void processAutoClose(); // not sure that this needs to be a 'slot', 'private' might be enough

private:
  Ui::qtProgressDialog* ui;

  void initialize(); // common initialization
  void addMessageText(
    QString message,
    MessageType messageType);   // turns messages into HTML for display
  void rebuildMessageHistory(); // applies the message type filters

  enum Icons
  {
    None = 0,
    InfoIcon = 1,
    NoInfoIcon = 2,
    WarningIcon = 4,
    NoWarningIcon = 8,
    ErrorIcon = 16,
    NoErrorIcon = 32
  };
  friend Icons operator|(Icons a, Icons b)
  {
    return static_cast<Icons>(static_cast<int>(a) | static_cast<int>(b));
  }
  friend Icons& operator|=(Icons& a, Icons b)
  {
    return a = static_cast<Icons>(static_cast<int>(a) | static_cast<int>(b));
  }
  void setButtonIcons(Icons icons);

  QVector<QPair<QString, MessageType>> m_progressMessages; // stores all messages (for rebuilding
    // the Message Box with different filters)

  QMutex* m_pMessageMutex = nullptr; // prevents Message Box corruption if a message
                                     // is added mid-rebuild
  QVector<QPair<QString, MessageType>>
    m_messageQueue; // temporarily stores incoming messages for after the Mutex is released

  bool m_bAutoClose;               // tracks if autoClose will be used
  bool m_bAutoDisableCancelButton; // tracks if cancel button will be auto-disabled at completion
  QTime m_startTime;               // internal tracking of start time for minDuration calculations
  uint m_minDuration;    // user-specified minimum duration that the dialog can be open (prevent
                         // "visibility strobing" for fast processes)
  uint m_autoCloseDelay; // user-specified delay of closing after maxProgress has been reached
  uint m_functionalAutoCloseDelay;  // minDuration-adusted value for autoCloseDelay
  int m_maxProgress;                // stores the madProgress to see when to trigger auto-close
  uint m_remainingAutoCloseSeconds; // keeps track of remaining seconds as timer ticks down
  bool m_bShowMessageIcons; // tracks if icons will be displayed inline with messages (to the left)

  QPixmap m_infoPixmap;
  QPixmap m_noInfoPixmap;
  QPixmap m_warningPixmap;
  QPixmap m_noWarningPixmap;
  QPixmap m_errorPixmap;
  QPixmap m_noErrorPixmap;
  QString m_infoIconHTML;
  QString m_warningIconHTML;
  QString m_errorIconHTML;

  QTimer* m_autoCloseTimer;
};

#endif // smtk_simulation_ace3p_qt_qtProgressDialog
