// 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 WTEXT_H_
#define WTEXT_H_

#include <Wt/WInteractWidget>
#include <Wt/WString>

namespace Wt {

/*! \class WText Wt/WText Wt/WText
 *  \brief A widget that renders (XHTML) text.
 *
 * The text is provided through a WString, which may either hold a
 * literal text, or a key to localized text which is looked up in
 * locale dependent XML files (see WString::tr()).
 *
 * Use setTextFormat() to configure the textFormat of the text. The
 * default textFormat is Wt::XHTMLText, which allows XHMTL markup to
 * be included in the text. Tags and attributes that indicate "active"
 * content are not allowed and stripped out, to avoid security risks
 * exposed by JavaScript such as the common web-based <a
 * href="http://en.wikipedia.org/wiki/Cross_site_scriptingCross-Site">
 * Cross-Site Scripting (XSS)</a> malicious attack. XSS is the
 * situation where one user of your web application is able to execute
 * a script in another user's browser while your application only
 * intended to display a message entered by the mailicious user to the
 * other user. To defeat this attack, %Wt assumes that content in a
 * %WText is intended to be passive, and not contain any scripting
 * elements.
 *
 * The Wt::PlainText format will display the text literally
 * (escaping any HTML special characters).
 *
 * In some situations, Wt::XHTMLUnsafeText may be useful to explicitly
 * allow scripting content. Like XHTMLText, it allows XHTML markup,
 * but it also allows potentially dangerous tags and attributes. Use
 * this if you're sure that a user cannot interfere with the text set,
 * and XHTMLText is too limiting.
 *
 * %WText is by default \link WWidget::setInline()
 * inline\endlink, unless the XHTML contents starts with an
 * element such as <tt>&lt;div&gt;</tt>, <tt>&lt;h&gt;</tt> or
 * <tt>&lt;p&gt;</tt> that is displayed as a block, in which case the
 * widget will also display as a block.
 *
 * \if cpp
 * Usage examples:
 * \code
 * Wt::WContainerWidget *container = new Wt::WContainerWidget();
 *
 * // display an XHTML text:
 * container->addWidget(new Wt::WText("Hello <i>dear</i> visitor."));
 *
 * // display a plain text:
 * container->addWidget(new Wt::WText("The <i> tag displays italic text.", Wt::PlainText));
 *
 * // display an XHTML fragment from a resource bundle:
 * container->addWidget(new Wt::WText(tr("introduction")));
 * \endcode
 * \endif
 *
 * <h3>CSS</h3>
 *
 * The widget corresponds to an HTML <tt>&lt;span&gt;</tt> tag or an
 * HTML <tt>&lt;div&gt;</tt> depending on whether the widget is inline.
 *
 * This widget does not provide styling, 
 * and can be styled using inline or external CSS as appropriate.
 *
 * \sa WApplication::setLocale()
 * \if cpp
 * \sa WApplication::messageResourceBundle()
 * \endif
 */
class WT_API WText : public WInteractWidget
{
public:
  /*! \brief Creates a text widget with an empty text.
   */
  WText(WContainerWidget *parent = 0);

  /*! \brief Creates a text widget with given text.
   *
   * The textFormat is set to Wt::XHTMLText, unless the \p text is
   * literal (not created using WString::tr()) and it could not be
   * parsed as valid XML. In that case the textFormat is set to
   * Wt::PlainText.
   *
   * Therefore, if you wish to use Wt::XHTMLText, 
   * but cannot be sure about \p text being valid XML, 
   * you should verify that the textFormat() is Wt::XHTMLText
   * after construction.
   *
   * The XML parser will silently discard malicious tags and
   * attributes for literal Wt::XHTMLText text.
   */
  WText(const WString& text, WContainerWidget *parent = 0);

  /*! \brief Creates a text widget with given text and format
   *
   * If <i>textFormat</i> is Wt::XHTMLText and \p text is not
   * literal (not created using WString::tr()), then if the
   * \p text could not be parsed as valid XML, the textFormat is
   * changed to Wt::PlainText.
   *
   * Therefore, if you wish to use Wt::XHTMLText, but cannot be sure
   * about \p text being valid XML, you should verify that the
   * textFormat() is Wt::XHTMLText after construction.
   *
   * The XML parser will silently discard malicious tags and
   * attributes for literal Wt::XHTMLText text.
   */
  WText(const WString& text, TextFormat textFormat,
	WContainerWidget *parent = 0);

  /*! \brief Destructor.
   */
  ~WText();

  /*! \brief Returns the text.
   *
   * When a literal XHTMLFormatted text was set, this may differ from
   * the text that was set since malicious tags/attributes may have
   * been stripped.
   *
   * \sa setText(const WString&)
   */
  const WString& text() const { return text_.text; }

  /*! \brief Sets the text.
   *
   * When the current format is Wt::XHTMLText, and
   * \p text is literal (not created using WString::tr()), it is
   * parsed using an XML parser which discards malicious tags and
   * attributes silently. When the parser encounters an XML parse
   * error, the textFormat is changed to Wt::PlainText.
   *
   * Returns whether the text could be set using the current
   * textFormat. A return value of \c false indicates that the textFormat
   * was changed in order to be able to accept the new text.
   *
   * \sa text(), setText()
   */
  bool setText(const WString& text);

  /*! \brief Sets the text format.
   *
   * The textFormat controls how the string should be interpreted:
   * either as plain text, which is displayed literally, or as
   * XHTML-markup.
   *
   * When changing the textFormat to Wt::XHTMLText, and the
   * current text is literal (not created using WString::tr()), the
   * current text is parsed using an XML parser which discards
   * malicious tags and attributes silently. When the parser
   * encounters an XML parse error, the textFormat is left unchanged,
   * and this method returns false.
   *
   * Returns whether the textFormat could be set for the current text.
   *
   * The default format is Wt::XHTMLText.
   */
  bool setTextFormat(TextFormat format);

  /*! \brief Returns the text format.
   *
   * \sa setTextFormat()
   */
  TextFormat textFormat() const { return text_.format; }

  /*! \brief Configures word wrapping.
   *
   * When \p wordWrap is \c true, the widget may break lines, creating a
   * multi-line text. When \p wordWrap is \c false, the text will displayed
   * on a single line, unless the text contains end-of-lines (for
   * Wt::PlainText) or &lt;br /&gt; tags or other block-level tags
   * (for Wt::XHTMLText).
   *
   * The default value is \c true.
   *
   * \sa wordWrap()
   */
  void setWordWrap(bool wordWrap);

  /*! \brief Returns whether the widget may break lines.
   *
   * \sa setWordWrap(bool)
   */
  bool wordWrap() const { return flags_.test(BIT_WORD_WRAP); }

  /*! \brief Sets padding inside the widget
   *
   * Setting padding has the effect of adding distance between the
   * widget children and the border, for a WText padding is only supported
   * on the left and/or right.
   */
  void setPadding(const WLength& padding, WFlags<Side> sides = Left | Right);

  /*! \brief Returns the padding set for the widget.
   *
   * \sa setPadding(const WLength&, WFlags<Side>)
   */
  WLength padding(Side side) const;

  /*! \brief Enables internal path encoding of anchors in the XHTML text.
   *
   * Anchors to internal paths are represented differently depending
   * on the session implementation (plain HTML, Ajax or HTML5
   * history). By enabling this option, anchors which reference an
   * internal path (by referring a URL of the form
   * <tt>href="#/..."</tt>), are re-encoded to link to the internal
   * path.
   *
   * When using Wt::XHTMLText (or Wt::XHTMLUnsafeText) formatted text,
   * the text is pasted verbatim in the browser (with the exception of
   * XSS filtering if applicable). With this option, however, the
   * XHTML text may be transformed at the cost of an additional XML
   * parsing step.
   *
   * The default value is \c false.
   *
   * \sa WAnchor::setInternalPath()
   */
  void setInternalPathEncoding(bool enabled);

  /*! \brief Returns whether internal paths are encoded.
   *
   * \sa setInternalPathEncoding()
   */
  bool hasInternalPathEncoding() const
    { return flags_.test(BIT_ENCODE_INTERNAL_PATHS); }

  virtual void refresh();

private:
  struct RichText {
    RichText();

    WString text;
    TextFormat format;

    bool setText(const WString& text);
    bool setFormat(TextFormat format);
    bool checkWellFormed();
    std::string formattedText() const;
  };

  RichText text_;

  static const int BIT_WORD_WRAP = 0;
  static const int BIT_TEXT_CHANGED = 1;
  static const int BIT_WORD_WRAP_CHANGED = 2;
  static const int BIT_PADDINGS_CHANGED = 3;
  static const int BIT_ENCODE_INTERNAL_PATHS = 4;

  std::bitset<5> flags_;

  std::string formattedText() const;
  void autoAdjustInline();

  WLength *WT_ARRAY padding_;

protected:
  virtual void           render(WFlags<RenderFlag> flags);
  virtual void           updateDom(DomElement& element, bool all);
  virtual DomElementType domElementType() const;
  virtual void           propagateRenderOk(bool deep);

  friend class WAbstractToggleButton;
  friend class WLabel;
  friend class WPushButton;
};

}

#endif // WTEXT_H_
