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

#include <Wt/WContainerWidget>
#include <Wt/WJavaScript>
#include <Wt/WLink>

namespace Wt {

  namespace Impl { 
    class AreaWidget;
  }

/*! \class WAnchor Wt/WAnchor Wt/WAnchor
 *  \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 setTarget(AnchorTarget)
 * setTarget(TargetNewWindow)\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 When linking to a \p resource, the anchor does not assume
 * ownership of \p resource, so that you may share the same resources
 * for several anchors.
 * \endif
 *
 * \if cpp
 * Usage example:
 * \code
 * WAnchor *a;
 *
 * // Create an anchor that links to a URL
 * a = new WAnchor("http://www.webtoolkit.eu/", "Wt web toolkit", this);
 *
 * // Create an anchor that links to an internal path
 * a = new WAnchor(WLink(WLink::InternalPath, "/docs/" + myDocName()), "Doc", this);
 * //   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 = new PdfResource(this); // serializes to a PDF file.
 * a = new WAnchor(r, "PDF version", this);
 * a->setTarget(TargetNewWindow);
 * \endcode
 * \endif
 *
 * %WAnchor is an \link WWidget::setInline(bool) inline \endlink widget.
 *
 * \note If you set a text or image using one of the API methods like
 * setText() or setImage() or a constructor, you should not attempt to
 * remove all contents (using clear(), or provide a layout (using
 * setLayout()), as this will result in undefined behaviour: the text
 * or image are simply inserted as widgets into the container.
 *
 * <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(WContainerWidget *parent = 0);

  /*! \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, WContainerWidget *parent = 0);

#ifdef WT_TARGET_JAVA
  /*! \brief Creates an anchor linking to a URL (<b>deprecated</b>).
   *
   * \deprecated Use WAnchor(const WLink&, WContainerWidget *) instead.
   */
  WAnchor(const std::string& url, WContainerWidget *parent = 0);

  /*! \brief Creates an anchor linking to a resource (<b>deprecated</b>).
   *
   * The \p resource specifies application-dependent content that may
   * be generated by your application on demand.
   *
   * The anchor does not assume ownership of \p resource, so that you
   * may share the same resources for several anchors.
   *
   * \deprecated Use WAnchor(const WLink&, WContainerWidget *) instead.
   */
  WAnchor(WResource *resource, WContainerWidget *parent = 0);
#endif

  /*! \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, WContainerWidget *parent = 0);

#ifdef WT_TARGET_JAVA
  /*! \brief Creates an anchor linking to a URL with a text (<b>deprecated</b>).
   *
   * \deprecated Use WAnchor(const WLink&, const WString&, WContainerWidget *) instead.
   */
  WAnchor(const std::string& url, const WString& text,
	  WContainerWidget *parent = 0);

  /*! \brief Creates an anchor linking to a resource with a text
   *         (<b>deprecated</b>).
   *
   * The \p resource specifies application-dependent content that may
   * be generated by your application on demand.
   *
   * The anchor does not assume ownership of \p resource, so that you
   * may share the same resources for several anchors.
   *
   * \deprecated Use WAnchor(const WLink&, const WString&, WContainerWidget *) instead.
   */
  WAnchor(WResource *resource, const WString& text,
	  WContainerWidget *parent = 0);
#endif // WT_TARGET_JAVA

  /*! \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, WImage *image, WContainerWidget *parent = 0);

#ifdef WT_TARGET_JAVA
  /*! \brief Creates an anchor linking to a URL with an image (<b>deprecated</b>).
   *
   * \deprecated Use WAnchor(const WLink&, WImage *, WContainerWidget *)
   *             instead.
   */
  WAnchor(const std::string& ref, WImage *image, WContainerWidget *parent = 0);

  /*! \brief Creates an anchor linking to a resource with an image (<b>deprecated</b>).
   *
   * \deprecated Use WAnchor(const WLink&, WImage *, WContainerWidget *)
   *             instead.
   */
  WAnchor(WResource *resource, WImage *image, WContainerWidget *parent = 0);
#endif // WT_TARGET_JAVA

  /*! \brief Sets the link.
   *
   * The link may hold a URL, a resource, or an internal path.
   *
   * When the link points to a \link WLink::Resource resource\endlink,
   * the contents of the link may be generated by your application on
   * demand.
   *
   * When the link points to an \link WLink::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 linked URL (<b>deprecated</b>).
   *
   * \deprecated Use setLink() instead. 
   */
  void setRef(const std::string& url);

  /*! \brief Sets a link to an internal path (<b>deprecated</b>).
   *
   * \if cpp
   * \note the \p path should be UTF8 encoded (we may fix the API
   *       to use WString in the future).
   * \endif
   *
   * \deprecated Use setLink() instead.
   */
  void setRefInternalPath(const std::string& path);

  /*! \brief Returns the destination URL or internal path (<b>deprecated</b>).
   *
   * When the anchor links to a resource, the current resource URL is
   * returned. When the anchor links to an internal path, the
   * internal path is returned. Otherwise, the linked URL is returned.
   *
   * \deprecated Use link() instead.
   */
  std::string& ref() const;

  /*! \brief Sets a destination resource (<b>deprecated</b>).
   *
   * The anchor does not assume ownership of the resource.
   *
   * \deprecated Use setLink() instead.
   */
  void setResource(WResource *resource);

  /*! \brief Returns the destination resource (<b>deprecated</b>).
   *
   * Returns \c 0 if no resource has been set.
   *
   * \deprecated Use link() instead.
   */
  WResource *resource() const;

  /*! \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 XHTMLText.
   *
   * \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().
   *
   * Ownership of the image is transferred to the anchor.
   */
  void setImage(WImage *image);

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

  /*! \brief Sets the location where the linked content should be
   *         displayed.
   *
   * By default, the linked content is displayed in the application
   * (Wt::TargetSelf). When the destination is an HTML document, the
   * application is replaced with the new document. When the link is
   * to a document that cannot be displayed in the browser, it is
   * offered for download or opened using an external program,
   * depending on browser settings.
   *
   * By setting \p target to Wt::TargetNewWindow, the destination
   * is displayed in a new browser window or tab.
   *
   * \sa target()
   */
  void setTarget(AnchorTarget target);

  /*! \brief Returns the location where the linked content should be
   *         displayed.
   *
   * \sa setTarget()
   */
  AnchorTarget target() const { return linkState_.target; }

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

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

    WLink link;
    AnchorTarget target;
    JSlot *clickJS; 
  };

  LinkState linkState_;

  WText *text_;
  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);
  virtual DomElementType domElementType() const;
  virtual void propagateRenderOk(bool deep);
  virtual void enableAjax();

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

}

#endif // WANCHOR_H_
