// 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>

namespace Wt {

class WText;
class WImage;

/*! \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. The anchor may contain a label
 * text, an image, or any other widget (as it inherits from
 * WContainerWidget). If you 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
 * Usage example:
 * \code
 * WAnchor *a;
 *
 * // Create an anchor that references a URL
 * a = new WAnchor("http://www.webtoolkit.eu/", "Wt web toolkit", this);
 *
 * // Create an anchor that references an internal path
 * a = new WAnchor(this);
 * a->setRefInternalPath("/docs/" + myDocName());
 * //   and listen to the corresponding change in internal path
 * WApplication::instance()->internalPathChanged().connect(this, &DocsListWidget::onInternalPathChange);
 *
 * // Create an anchor that references 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 referring to a URL.
   */
  WAnchor(const std::string& url, WContainerWidget *parent = 0);

  /*! \brief Creates an anchor referring a resource.
   *
   * 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.
   *
   * \sa WResource
   */
  WAnchor(WResource *resource, WContainerWidget *parent = 0);

  /*! \brief Creates an anchor referring to a URL, using a text message.
   */
  WAnchor(const std::string& url, const WString& text,
	  WContainerWidget *parent = 0);

  /*! \brief Creates an anchor referring to a resource, using a text message.
   *
   * 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.
   */
  WAnchor(WResource *resource, const WString& text,
	  WContainerWidget *parent = 0);

  /*! \brief Creates an anchor referring to a URL, using an image.
   *
   * Ownership of the image is transferred to the anchor.
   */
  WAnchor(const std::string& ref, WImage *image, WContainerWidget *parent = 0);

  /*! \brief Creates an anchor referring to a resource, using an
   *  image.
   *
   * 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.
   *
   * Ownership of the image is transferred to the anchor.
   */
  WAnchor(WResource *resource, WImage *image, WContainerWidget *parent = 0);

  virtual ~WAnchor();

  /*! \brief Sets the destination URL.
   *
   * This method should not be used when the anchor has been pointed
   * to a dynamically generated resource using setResource().
   *
   * \sa setResource(), setRefInternalPath()
   */
  void setRef(const std::string& url);

  /*! \brief Sets the destination URL as an internal path.
   *
   * Sets the anchor to point to the internal path \p path. When
   * the anchor is activated, the internal path is set to \p path,
   * and the WApplication::internalPathChanged() signal is
   * emitted.
   *
   * This is the easiest way to let the application participate in
   * browser history, and generate URLs that are bookmarkable and search
   * engine friendly.
   *
   * Internally, this method sets the destination URL using: \code
   * setRef(WApplication::instance()->bookmarkUrl(path)) \endcode
   *
   * The clicked() signal is connected to a slot that changes the internal
   * path by calling
   * \code
   * WApplication::instance()->setInternalPath(ref(), true);
   * \endcode
   *
   * \sa setRef(), setResource()
   *
   * \sa WApplication::bookmarkUrl(), WApplication::setInternalPath()
   */
  void setRefInternalPath(const std::string& path);

  /*! \brief Returns the destination URL.
   *
   * When the anchor refers to a resource, the current resource URL is
   * returned. When the anchor refers to an internal path, the
   * internal path is returned. Otherwise, the URL is returned that
   * was set using setRef().
   *
   * \sa setRef(), WResource::url()
   */
  const std::string& ref() const { return ref_; }

  /*! \brief Sets a destination resource.
   *
   * A resource specifies application-dependent content, which may be
   * generated by your application on demand.
   *
   * This sets the \p resource as the destination of the anchor,
   * and is an alternative to setRef(). The resource may be cleared by
   * passing \p resource = \c 0.
   *
   * The anchor does not assume ownership of the resource.
   *
   * \sa setRef()
   */
  void setResource(WResource *resource);

  /*! \brief Returns the destination resource.
   *
   * Returns \c 0 if no resource has been set.
   *
   * \sa setResource()
   */
  WResource *resource() const { return resource_; }

  /*! \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
   * &lt;br /&gt; tags or other block-level tags.
   *
   * 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;

  /*! \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 referred content should be
   *         displayed.
   *
   * By default, the referred 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 reference
   * is 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 referred content should be
   *         displayed.
   *
   * \sa setTarget()
   */
  AnchorTarget target() const { return target_; }

private:
  static const int BIT_REF_INTERNAL_PATH = 0;
  static const int BIT_REF_CHANGED = 1;
  static const int BIT_TARGET_CHANGED = 2;

  std::string    ref_;
  WResource     *resource_;
  WText         *text_;
  WImage        *image_;
  AnchorTarget   target_;
  std::bitset<3> flags_;

  JSlot *changeInternalPathJS_;

  void resourceChanged();

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

}

#endif // WANCHOR_H_
