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

namespace Wt {

class WText;
class WImage;

/*! \brief Enumeration that specifies where the target of an anchor should
 *         be displayed. 
 */
enum AnchorTarget {
  TargetSelf,      //!< Show Instead of the application
  TargetThisWindow,//!< Show in the top level frame of the application window
  TargetNewWindow  //!< Show in a separate new tab or window
};

/*! \class WAnchor Wt/WAnchor Wt/WAnchor
 *  \brief A widget that represents an HTML anchor (to link to other documents)
 *
 * %WAnchor is an \link WWidget::setInline(bool) inline \endlink widget.
 *
 * Use an anchor to link to an internal path or another web page,
 * document or resource. The anchor may contain text, image, or any
 * other widget (since it inherits from WContainerWidget). A click
 * will activate the target link.
 *
 * \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.
 */
class WT_API WAnchor : public WContainerWidget
{
public:
  /*! \brief Create an anchor.
   */
  WAnchor(WContainerWidget *parent = 0);

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

  /*! \brief Create an anchor referring to a resource.
   *
   * A resource specifies application-dependent content, which may be
   * generated by your application on demand.
   *
   * The anchor does not assume ownership of the resource.
   */
  WAnchor(WResource *resource, WContainerWidget *parent = 0);

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

  /*! \brief Create an anchor reffering to a resource, using a text message.
   *
   * A resource specifies application-dependent content, which may be
   * generated by your application on demand.
   *
   * The anchor does not assume ownership of the resource.
   */
  WAnchor(WResource *resource, const WString& text,
	  WContainerWidget *parent = 0);

  /*! \brief Create an anchor reffering 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 Create an anchor reffering to a resource, using an image.
   *
   * A resource specifies application-dependent content, which may be
   * generated by your application on demand.
   *
   * The anchor does not assume ownership of the resource.
   *
   * Ownership of the image is transferred to the anchor.
   */
  WAnchor(WResource *resource, WImage *image, WContainerWidget *parent = 0);

  /*! \brief Set 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 Set the destination URL to an internal path.
   *
   * Sets the anchor to point to the internal path <i>path</i>. When
   * the anchor is activated, the internal path is set to <i>path</i>,
   * and the WApplication::internalPathChanged signal is emitted. The
   * path change is handled within the current session.
   *
   * This is the easiest way to let the application participate in
   * browser history, and generate URLs that are bookmarkable.
   *
   * Internally, this method binds sets the destination URL using:
   * \code
   * setRef(wApp->bookmarkUrl(path))
   * \endcode
   * The \link WAnchor::clicked clicked\endlink signal is connected
   * to a slot that changes the internal path using
   * \code
   * wApp->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::generateUrl()
   */
  const std::string& ref() const { return ref_; }

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

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

  /*! \brief Sets a text label.
   *
   * 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 Configure text word wrapping.
   *
   * When <i>on</i> is true, the text set with setText() may be broken
   * up over multiple lines. When <i>on</i> is 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 true.
   *
   * \sa wordWrap()
   */
  void setWordWrap(bool on);

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

  /*! \brief Set an image.
   *
   * If an image was previously set, it is deleted. The <i>image</i>
   * is added using addWidget().
   *
   * Ownership of the image is transferred to the anchor.
   */
  void setImage(WImage *image);

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

  /*! \brief Set 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 <i>target</i> 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_CHANGED = 0;
  static const int BIT_TARGET_CHANGED = 1;

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

  void resourceChanged();

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

}

#endif // WANCHOR_H_
