// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2011 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WLINK_H_
#define WLINK_H_

#ifndef WT_CNOR
#include <boost/variant.hpp>
#else
#include <boost/any.hpp>
#endif

#include <Wt/WGlobal>

#include <string>

namespace Wt {

/*! \brief A value class that defines a hyperlink target.
 *
 * This class abstracts a link target. Depending on the context, it
 * may reference a URL, a dynamic \link WResource resource\endlink, or
 * (for certain usages) an internal path.
 *
 * \sa WAnchor, WImage, WMediaPlayer, WPopupMenuItem, WPushButton
 */
class WT_API WLink
{
public:
  /*! \brief An enumeration for a link type.
   *
   * \sa type()
   */
  enum Type {
    Url,          //!< A static URL.
    Resource,     //!< A dynamic resource.
    InternalPath  //!< An internal path.
  };

  /*! \brief Default constructor.
   *
   * This constructs a null link.
   */
  WLink();

  /*! \brief Creates a link to a (static) URL.
   *
   * \sa setUrl()
   */
  WLink(const char *url);

  /*! \brief Creates a link to a (static) URL.
   *
   * \sa setUrl()
   */
  WLink(const std::string& url);

  /*! \brief Creates a link to a (static) URL or an internal path.
   *
   * Using this constructor, you can create a link to a static URL (\p
   * type == WLink::Url) or an internal path (\p type ==
   * WLink::InternalPath). For an internal path, the \p value will
   * be interpreted as a UTF8 encoded string.
   *
   * \sa setUrl(), setInternalPath()
   */
  WLink(Type type, const std::string& value);

  /*! \brief Creates a link to a resource.
   *
   * \if cpp
   * Ownership of the \p resource is not transferred to the link (or to
   * the widget that deals with it), to allow resources to be shared.
   * \endif
   *
   * \sa setResource()
   */
  WLink(WResource *resource);

  /*! \brief Returns the link type.
   *
   * The type is implicitly set depending on the constructor or after
   * calling setUrl(), setResource() or setInternalPath().
   *
   * The default type for a null link is WLink::Url.
   */
  Type type() const { return type_; }

  /*! \brief Returns whether the link is unspecified.
   *
   * A null link is a link created using the default constructor and
   * points to nowhere.
   *
   * \sa WLink()
   */
  bool isNull() const;

  /*! \brief Sets the link URL.
   *
   * This sets the type to WLink::Url.
   */
  void setUrl(const std::string& url);

  /*! \brief Returns the link URL.
   *
   * The return value is the URL set by setUrl(), the resource URL of
   * the resource set using setResource(), or the canonical URL of
   * an internal path within the current application context.
   */
  std::string url() const;

  /*! \brief Sets the link resource.
   *
   * This sets the type to WLink::Resource.
   *
   * \if cpp
   * Ownership of the \p resource is not transferred to the link (or to
   * the widget that deals with it), to allow resources to be shared.
   * \endif
   */
  void setResource(WResource *resource);

  /*! \brief Returns the link resource.
   *
   * This returns the resource previously set using setResource(), or \c 0.
   *
   * \sa setResource()
   */
  WResource *resource() const;

  /*! \brief Sets the link internal path.
   *
   * This points the link to the given internal path.
   */
  void setInternalPath(const WT_USTRING& internalPath);

  /*! \brief Returns the internal path.
   *
   * This returns the internal path perviously set using setInternalPath(),
   * or an empty string otherwise.
   *
   * \sa setInternalPath().
   */
  WT_USTRING internalPath() const;

  /*! \brief Comparison operator.
   */
  bool operator== (const WLink& other) const;

  /*! \brief Comparison operator.
   */
  bool operator!= (const WLink& other) const;

  std::string resolveUrl(WApplication *app) const;

private:
  Type type_;
#ifndef WT_CNOR
  boost::variant<std::string, WResource *> value_;
#else
  boost::any value_;
#endif

  JSlot *manageInternalPathChange(WApplication *app, WInteractWidget *widget,
				  JSlot *slot) const;

  friend class WAnchor;
  friend class WAbstractArea;
};

}

#endif // WLINK_H_
