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

#include <Wt/WInteractWidget>
#include <Wt/WLink>

namespace Wt {

  namespace Impl {
    class MapWidget;
  }

  class WAbstractArea;

/*! \class WImage Wt/WImage Wt/WImage
 *  \brief A widget that displays an image.
 *
 * The image may be specified either as a URL, or may be dynamically
 * generated by a WResource.
 *
 * You may listen to events by attaching event listeners to signals
 * such as clicked(). Since mouse events pass the coordinates through
 * a WMouseEvent object, it is possible to react to clicks in specific
 * parts of the image. An alternative is to define interactive areas
 * on the image using addArea(), which in addition allows to have
 * customized tool tips for certain image areas (using
 * WAbstractArea::setToolTip()).
 *
 * \if cpp
 * Usage example:
 * \code
 * Wt::WImage *img = new Wt::WImage("images/johnny_cash.png", this);
 * img->setAlternateText("Johnny Cash sings a song");
 * \endcode
 * \endif
 *
 * %WImage is an \link WWidget::setInline(bool) inline \endlink widget.
 *
 * <h3>CSS</h3>
 *
 * The widget corresponds to the HTML <tt>&lt;img&gt;</tt> tag and
 * does not provide styling. It can be styled using inline or external
 * CSS as appropriate.
 *
 * \sa WResource, WPaintedWidget
 */
class WT_API WImage : public WInteractWidget
{
public:
  /*! \brief Creates an empty image widget.
   */
  WImage(WContainerWidget *parent = 0);

  /*! \brief Creates an image widget with a given image link.
   *
   * The \p imageLink may link to a URL or resource.
   */
  WImage(const WLink& imageLink, WContainerWidget *parent = 0);

  /*! \brief Creates an image widget with a given image link and alternate text.
   *
   * The \p imageLink may link to a URL or resource.
   */
  WImage(const WLink& imageLink, const WString& altText,
	 WContainerWidget *parent = 0);

#ifdef WT_TARGET_JAVA
  /*! \brief Creates an image widget with given image URL (<b>deprecated</b>).
   *
   * \deprecated Use WImage(const WLink&, WContainerWidget *) instead.
   */
  WImage(const std::string& imageRef, WContainerWidget *parent = 0);

  /*! \brief Creates an image widget with given image URL and alternate text
   *         (<b>deprecated</b>).
   *
   * \deprecated Use WImage(const WLink&, const WString&, WContainerWidget *) instead.
   */
  WImage(const std::string& imageRef, const WString& altText,
	 WContainerWidget *parent = 0);

  /*! \brief Creates an image widget with given image resource and alternate
   *         text (<b>deprecated</b>).
   *
   * \deprecated Use WImage(const WLink&, const WString&, WContainerWidget *) instead.
   */
  WImage(WResource *resource, const WString& altText,
	 WContainerWidget *parent = 0);
#endif // WT_TARGET_JAVA

  ~WImage();

  /*! \brief Sets an alternate text.
   *
   * The alternate text should provide a fallback for browsers that do
   * not display an image. If no sensible fallback text can be
   * provided, an empty text is preferred over nonsense.
   *
   * This should not be confused with toolTip() text, which provides
   * additional information that is displayed when the mouse hovers
   * over the image.
   *
   * The default alternate text is an empty text ("").
   *
   * \sa alternateText()
   */
  void setAlternateText(const WString& text);

  /*! \brief Returns the alternate text.
   *
   * \sa setAlternateText()
   */
  const WString& alternateText() const { return altText_; }

  /*! \brief Sets the image link.
   *
   * The image may be specified as a URL or as a resource. A resource
   * specifies application-dependent content, which may be used to
   * generate an image on demand.
   */
  void setImageLink(const WLink& link);

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

  /*! \brief Sets the image URL (<b>deprecated</b>).
   *
   * \deprecated Use setImageLink() instead.
   */
  void setImageRef(const std::string& url);

  /*! \brief Returns the image URL (<b>deprecated</b>).
   *
   * When the image is specified as a resource, this returns the current
   * resource URL.
   *
   * \deprecated Use imageLink() instead.
   */
  const std::string imageRef() const;

  /*! \brief Sets the image resource (<b>deprecated</b>).
   *
   * \deprecated Use setImageLink() instead.
   */
  void setResource(WResource *resource);

  /*! \brief Returns the image resource (<b>deprecated</b>.
   *
   * Returns \c 0 if no image resource was set.
   *
   * \deprecated Use setImageLink() instead.
   */
  WResource *resource() const;

  /*! \brief Adds an interactive area.
   *
   * Adds the \p area which listens to events in a specific region
   * of the image. Areas are organized in an indexed list, to which
   * the given \p area is appended. When areas overlap, the area
   * with the lowest index receives the event.
   *
   * Ownership of the \p area is transferred to the image.
   *
   * \sa insertArea(int, WAbstractArea *)
   *
   * \note Currently it is not possible to add a first area after the image
   *       has been rendered. If you want to use interactive areas you need
   *       to add one immediately.
   */
  void addArea(WAbstractArea *area);

  /*! \brief Inserts an interactive area.
   *
   * Inserts the \p area which listens to events in the
   * coresponding area of the image. Areas are organized in a list,
   * and the <i>area</i> is inserted at index \p index. When areas
   * overlap, the area with the lowest index receives the event.
   *
   * Ownership of the \p area is transferred to the image.
   *
   * \sa addArea(WAbstractArea *)
   *
   * \note Currently it is not possible to add a first area after the image
   *       has been rendered. If you want to use interactive areas you need
   *       to add one immediately.
   */
  void insertArea(int index, WAbstractArea *area);

  /*! \brief Removes an interactive area.
   *
   * Removes the \p area from this widget, and also returns the
   * ownership.
   *
   * \sa addArea(WAbstractArea *)
   */
  void removeArea(WAbstractArea *area);

  /*! \brief Returns the interactive area at the given index.
   *
   * Returns \c 0 if \p index was invalid.
   *
   * \sa insertArea(int, WAbstractArea *)
   */
  WAbstractArea *area(int index) const;

  /*! \brief Returns the interactive areas set for this widget.
   *
   * \sa addArea()
   */
  const std::vector<WAbstractArea *> areas() const;

  /*! \brief Event emitted when the image was loaded.
   */
  EventSignal<>& imageLoaded();

  void setTargetJS(std::string targetJS);
  virtual std::string updateAreasJS();
  virtual std::string setAreaCoordsJS();

private:
  static const char *LOAD_SIGNAL;

  static const int BIT_ALT_TEXT_CHANGED = 0;
  static const int BIT_IMAGE_LINK_CHANGED = 1;
  static const int BIT_MAP_CREATED = 2;

  WString          altText_;
  WLink            imageLink_;
  Impl::MapWidget *map_;
  std::bitset<3>   flags_;
  std::string      targetJS_;

  void resourceChanged();

protected:
  virtual void getDomChanges(std::vector<DomElement *>& result,
			     WApplication *app);
  virtual void updateDom(DomElement& element, bool all);
  virtual void defineJavaScript();
  virtual void render(WFlags<RenderFlag> flags);
  virtual DomElementType domElementType() const;
  virtual void propagateRenderOk(bool deep);
  virtual std::string updateAreaCoordsJSON() const;

  friend class WLabel;
  friend class Impl::MapWidget;

  static std::vector<WAbstractArea *> noAreas_;
};

}

#endif // WIMAGE_H_
