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

#include <Wt/WContainerWidget.h>
#include <Wt/WJavaScript.h>
#include <Wt/WImage.h>
#include <Wt/WLink.h>

namespace Wt {

  namespace Impl {
    class AreaWidget;
  }

/*! \class WAnchor Wt/WAnchor.h Wt/WAnchor.h
 *  \brief A widget that represents an HTML anchor (to link to other documents).
 *
 * Use an anchor to link to another web page, document, internal
 * application path or a resource (which specifies
 * application-dependent content that may be generated by your
 * application on demand). The anchor may contain a label text, an
 * image, or any other widget (as it inherits from
 * WContainerWidget).
 *
 * If you link to a document or external url, and do not want the
 * application to terminate when the user follows the anchor, you must
 * use \link WLink.setTarget(LinkTarget)
 * link.setTarget(LinkTarget::NewWindow)\endlink. Even for non-HTML
 * documents, this may be important since pending Ajax requests are
 * cancelled if documents are not served within the browser window in
 * certain browsers.
 *
 * \if cpp
 * Usage example:
 * \code
 * WAnchor *a;
 *
 * // Create an anchor that links to a URL
 * a = addWidget(std::make_unique<Wt::WAnchor>("https://www.webtoolkit.eu/", "Wt web toolkit"));
 *
 * // Create an anchor that links to an internal path
 * a = addWidget(std::make_unique<Wt::WAnchor>(
 *       WLink(LinkType::InternalPath, "/docs/" + myDocName()), "Doc"));
 * //   and listen to the corresponding change in internal path
 * WApplication::instance()->internalPathChanged().connect(this, &DocsListWidget::onInternalPathChange);
 *
 * // Create an anchor that links to a resource
 * WResource *r = addChild(std::make_unique<PdfResource>()); // serializes to a PDF file.
 * a = addWidget(std::make_unique<Wt::WAnchor>(r, "PDF version"));
 * \endcode
 * \endif
 *
 * %WAnchor is an \link WWidget::setInline(bool) inline \endlink widget.
 *
 * <h3>CSS</h3>
 *
 * The widget corresponds to the HTML <tt>&lt;a&gt;</tt> tag and does
 * not provide styling. It can be styled using inline or external CSS
 * as appropriate.
 */
class WT_API WAnchor : public WContainerWidget
{
public:
  /*! \brief Creates an anchor.
   */
  WAnchor();

  /*! \brief Creates an anchor for the given link.
   *
   * The \p link may point to a URL, a dynamic resource, or an
   * internal path.
   *
   * \sa setLink()
   */
  WAnchor(const WLink& link);

  /*! \brief Creates an anchor for the given link with a text.
   *
   * The \p link may point to a URL, a dynamic resource, or an
   * internal path.
   *
   * \sa setLink(), setText()
   */
  WAnchor(const WLink& link, const WString& text);

  /*! \brief Creates an anchor for the given link with an image.
   *
   * \if cpp
   * Ownership of the image is transferred to the anchor.
   * \endif
   *
   * \sa setLink(), setImage()
   */
  WAnchor(const WLink& link, std::unique_ptr<WImage> image);

  /*! \brief Sets the link.
   *
   * The link may hold a URL, a resource, or an internal path.
   *
   * When the link points to a \link LinkType::Resource resource\endlink,
   * the contents of the link may be generated by your application on
   * demand.
   *
   * When the link points to an \link LinkType::InternalPath internal
   * path\endlink, activating the anchor will change the \link
   * WApplication::internalPath() application's internal path\endlink
   * or open a new session with the given path as \link
   * WEnvironment::internalPath() initial path\endlink). This is the
   * easiest way to let the application participate in browser
   * history, and generate URLs that are bookmarkable and search
   * engine friendly.
   */
  void setLink(const WLink& link);

  /*! \brief Returns the link.
   *
   * \sa setLink()
   */
  const WLink& link() const { return linkState_.link; }

  /*! \brief Sets the label text
   *
   * If no text was previously set, a new WText widget is added using
   * addWidget().
   */
  void setText(const WString& text);

  /*! \brief Returns the label text.
   *
   * Returns an empty string if no label was set.
   *
   * \sa setText()
   */
  const WString& text() const;

  /*! \brief Configures text word wrapping.
   *
   * When \p wordWrap is \c true, the text set with setText() may be
   * broken up over multiple lines. When \p wordWrap is \c false, the
   * text will displayed on a single line, unless the text contains
   * <tt>&lt;br /&gt;</tt> tags or other block-level tags.
   *
   * The default value is \c true.
   *
   * \sa wordWrap()
   */
  void setWordWrap(bool wordWrap);

  /*! \brief Configures the text format.
   *
   * The default text format is TextFormat::XHTML.
   *
   * \sa WText::setTextFormat()
   */
  void setTextFormat(TextFormat format);

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

  /*! \brief Returns whether the widget may break lines.
   *
   * \sa setWordWrap(bool)
   */
  bool wordWrap() const;

  /*! \brief Sets an image.
   *
   * If an image was previously set, it is deleted. The \p image
   * is added using addWidget().
   */
  void setImage(std::unique_ptr<WImage> image);

  /*! \brief Returns the image.
   *
   * Returns \c 0 if no image is set.
   *
   * \sa setImage()
   */
  WImage *image() const { return image_.get(); }

  virtual bool canReceiveFocus() const override;
  virtual int tabIndex() const override;
  virtual bool setFirstFocus() override;

private:
  static const int BIT_LINK_CHANGED = 0;
  static const int BIT_TARGET_CHANGED = 1;

  struct WT_API LinkState {
    LinkState();
    ~LinkState();

    WLink link;
    JSlot *clickJS;
  };

  LinkState linkState_;

  observing_ptr<WText> text_;
  observing_ptr<WImage> image_;
  std::bitset<2> flags_;

  void resourceChanged();

  static bool renderHRef(WInteractWidget *widget,
                         LinkState& linkState, DomElement& element);
  static void renderHTarget(LinkState& linkState, DomElement& element,
                            bool all);
  static void renderUrlResolution(WWidget *widget, DomElement& element,
                                  bool all);

protected:
  virtual void updateDom(DomElement& element, bool all) override;
  virtual DomElementType domElementType() const override;
  virtual void propagateRenderOk(bool deep) override;
  virtual void propagateSetEnabled(bool enabled) override;
  virtual void enableAjax() override;

  friend class WAbstractArea;
  friend class WPushButton;
  friend class Impl::AreaWidget;
};

}

#endif // WANCHOR_H_
