// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef EXT_MESSAGEBOX_H_
#define EXT_MESSAGEBOX_H_

#include <Wt/Ext/Dialog>
#include <Wt/Ext/ExtDllDefs.h>

namespace Wt {
  namespace Ext {

/*! \class MessageBox Wt/Ext/MessageBox Wt/Ext/MessageBox
 *  \brief A standard dialog for confirmation or to get simple user input.
 *
 * The message box shows a message in a dialog window, with a number
 * of buttons. These buttons may only be standard buttons.
 *
 * There are two distinct ways for using a %MessageBox, which reflect
 * the two ways of dealing with a Dialog box.
 *
 * The easiest way is using the static show() method, which shows a
 * message box, blocks the current thread, and returns the button that
 * was pressed by the user. Since this uses the Dialog::exec(), it suffers
 * from the same scalability issues.
 *
 * The more elaborate way is by creating a MessageBox, and connecting
 * the buttonClicked signal to a method. This method then interpretes
 * the result and deletes the message box.
 *
 * The API is slightly different from the WMessageBox API:
 * <ul>
 *   <li>no support for non-standard buttons (WMessageBox::addButton()),
 *     or access to buttons (WMessageBox::button()).
 *   <li>supports only Yes, No, Ok and Cancel buttons.</li>
 *   <li>supports more JavaScript like standard functionality, to prompt for
 *     input (enablePrompt(), enableTextArea()).</li>
 * </ul>
 *
 * \image html ExtMessageBox-1.png "Example of a MessageBox"
 *
 * \ingroup ext
 */
class WT_EXT_API MessageBox : public Dialog
{
public:
  using Dialog::show;

  /*! \brief Create an empty message box.
   *
   * The button labels may be set fixed English (if i18n = false), or fetched
   * from a resource bundle if i18n = true. In that case, the key for each
   * button is exactly the same as the English text.
   */
  MessageBox(bool i18n = false);

  /*! \brief Create a message box with given caption, text, icon, and
   *         buttons.
   *
   * The button labels may be set fixed English (if i18n = false), or fetched
   * from a resource bundle if i18n = true. In that case, the key for each
   * button is exactly the same as the English text.
   */
  MessageBox(const WString& caption, const WString& text, Icon icon,
	     WFlags<StandardButton> buttons, bool i18n = false);

  virtual ~MessageBox();

  /*! \brief Set the text for the message box.
   */
  void setText(const WString& text);

  /*! \brief Get the message box text.
   */
  const WString& text() const { return text_; }

  /*! \brief Set the icon.
   */
  void setIcon(Icon icon);

  /*! \brief Get the icon.
   */
  Icon icon() const { return icon_; }

  /*! \brief Set standard buttons for the message box.
   */
  void setButtons(WFlags<StandardButton> buttons);

  /*! \brief Get the standard buttons.
   */
  WFlags<StandardButton> buttons() const { return buttons_; }

  /*! \brief Get the result of this message box.
   *
   * This value is only defined after a button has been clicked.
   */
  StandardButton result() { return result_; }

  /*! \brief Show a single-line input field.
   *
   * A message box may contain either a prompt, or a text area field, but
   * not both. The value may be set using setValue() and retrieved using
   * value().
   *
   * \sa enableTextArea(), setValue(), value()
   */
  void enablePrompt(bool enable);

  /*! \brief Return if the messagebox may show a prompt.
   *
   * \sa enablePrompt()
   */  
  bool hasPrompt() const { return prompt_; }

  /*! \brief Show a multi-line input field.
   *
   * A message box may contain either a prompt, or a text area field, but
   * not both. The value may be set using setValue() and retrieved using
   * value().
   *
   * \sa enablePrompt(), setValue(), value()
   */
  void enableTextArea(bool enable);

  /*! \brief Return if the messagebox may show a prompt.
   *
   * \sa enableTextArea()
   */
  bool hasTextArea() const { return textArea_; }

  /*! \brief Set the value in the input field.
   *
   * \sa enableTextArea(), enablePrompt()
   */ 
  void setValue(const WString& value);

  /*! \brief Get the value of the input field.
   *
   * \sa enableTextArea(), enablePrompt()
   */ 
  const WString& value() const { return value_; }

  /*! \brief Convenience method to show a message box, blocking the current
   *         thread.
   *
   * Show a message box, blocking the current thread until the message box
   * is closed, and return the result.
   */
  static StandardButton show(const WString& caption,
			     const WString& text,
			     WFlags<StandardButton> buttons,
			     bool i18n = false);

  /*! \brief Convenience method to show a message box prompting for
   *         input, blocking the current thread.
   *
   * Show a message box that prompts for input, blocking the current
   * thread until the message box is closed, and return the result.
   *
   * When the user confirmed message box, the <i>value</i> is updated with
   * the edited value.
   */
  static StandardButton prompt(const WString& caption,
			       const WString& text,
			       WString& value, bool multiLine = false,
			       bool i18n = false);

  /*! \brief %Signal emitted when a button is clicked.
   */
  Signal<StandardButton>& buttonClicked() { return buttonClicked_; }

  /*! \brief Show or hide the message box.
   */
  virtual void setHidden(bool hidden,
			 const WAnimation& animation = WAnimation());

  virtual void refresh();

protected:
  void enableProgressBar(bool enable, bool infinite = false);
  void updateProgress(double value);
  virtual std::string buttonText(int buttonIndex) const;

private:
  Signal<StandardButton> buttonClicked_;
  WString                text_;
  WString                value_;
  WFlags<StandardButton> buttons_;
  Icon                   icon_;
  bool                   i18n_;
  bool                   prompt_;
  bool                   textArea_;
  bool                   progress_;
  double                 progressValue_;
  bool                   progressInfinite_;

  bool                   firstDisplay_;
  bool                  *catchDelete_;
  StandardButton         result_;
  JSignal<std::string, std::string> extButtonClicked_;

  void createConfig(std::ostream& config);
  void onClick(std::string buttonId, std::string value);
  virtual std::string renderRemoveJs();

  static const char *buttonText_[];
};

  }
}

#endif // EXT_MESSAGEBOX_
