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

#include <Wt/WAnchor> // for AnchorTarget

namespace Wt {

  namespace Impl {
    class AreaWidget;
  }

/*! \class WAbstractArea Wt/WAbstractArea Wt/WAbstractArea
 *  \brief Abstract base class for interactive areas in a widget.
 *
 * Use an %WAbstractArea (or rather, one of the non-abstract
 * specialized classes), to define interactivity that applies on a
 * part of a WImage or WPaintedWidget. The area may be defined using
 * different shapes through WRectArea, WCircleArea or WPolygonArea.
 *
 * \sa WImage::addArea(), WPaintedWidget::addArea()
 */
class WT_API WAbstractArea
{
public:
  /*! \brief Destructor.
   *
   * The are is automatically removed from the WImage or
   * WPaintedWidget to which it was added.
   *
   * \sa WImage::removeArea(), WPaintedWidget::removeArea()
   */
  virtual ~WAbstractArea();

  /*! \brief Specify that this area specifies a hole for another area.
   *
   * When set to true, this area will define an area that does not
   * provide interactivity. When it preceeds other, overlapping,
   * areas, it acts as if it cuts a hole in those areas.
   *
   * The default value is false.
   *
   * \sa isHole()
   */
  void setHole(bool hole);

  /*! \brief Returns whether this area specifies a hole.
   *
   * \sa setHole()
   */
  bool isHole() const { return hole_; }

  /*! \brief Set the destination URL.
   *
   * By setting a destionation URL, the area behaves like a
   * WAnchor.
   *
   * By default, no destination URL is set (ref = "").
   *
   * This method should not be used when the area has been pointed to
   * a dynamically generated resource using setResource().
   *
   * \sa setResource()
   *
   * \note Even when no destination URL is set, in some circumstances,
   *       a identity URL ('#') will be set on the underlying HTML
   *       &lt;area&gt; element (see also setCursor()).
   */
  void setRef(const std::string& ref);

  /*! \brief Returns the the destination URL.
   *
   * When the area refers to a resource, the current resource URL is
   * returned.
   *
   * \sa setRef(), WResource::generateUrl()
   */
  const std::string ref() const;

  /*! \brief Set a destination resource.
   *
   * A resource specifies application-dependent content, which may be
   * generated by your application on demand.
   *
   * By setting a resource, the area behaves like a WAnchor that
   * refers to the resource <i>resource</i>. The resource may be
   * cleared by passing <i>resource</i> = 0.
   *
   * The area 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;

  /*! \brief Specify the location where the referred content should be
   *         displayed.
   *
   * This configures the location where referred content should be
   * displayed, that was specified using setRef() or setResource().
   *
   * By default, the reference 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 setRef(), setResource(), target()
   */
  void setTarget(AnchorTarget target);

  /*! \brief Returns the location where the referred content should be
   *         displayed.
   *
   * \sa setTarget()
   */
  AnchorTarget target() const;

  /*! \brief Set 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 area.
   *
   * 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;

  /*! \brief Set the tooltip.
   *
   * The tooltip is displayed when the cursor hovers over the area.
   */
  void setToolTip(const WString& text);

  /*! \brief Returns the tooltip text.
   *
   * \sa setToolTip()
   */
  WString toolTip() const;

  void setStyleClass(const WString& styleClass);
  void setStyleClass(const char *styleClass);
  WString styleClass() const;

  /*! \brief Set the cursor.
   *
   * This sets the mouse cursor that is shown when the mouse pointer
   * is over the area. Most browsers only support PointingHandCursor,
   * which is activated by a non-empty ref.
   *
   * \sa setRef()
   */
  void setCursor(Cursor);

  /*! \brief Returns the cursor.
   *
   * \sa setCursor()
   */
  Cursor cursor() const;

  WImage *image() const;

private:
  Impl::AreaWidget *impl_;

public:
  /*! \brief Event signal emitted when a keyboard key is pushed down.
   *
   * The keyWentDown signal is the first signal emitted when a key is
   * pressed (before the keyPressed signal). Unlike \link
   * WAbstractArea::keyPressed keyPressed\endlink however it is also
   * emitted for modifier keys (such as "shift", "control", ...) or
   * keyboard navigation keys that do not have a corresponding
   * character.
   *
   * \sa WAbstractArea::keyPressed, WAbstractArea::keyWentUp
   */
  EventSignal<WKeyEvent>& keyWentDown;

  /*! \brief Event signal emitted when a "character" was entered.
   *
   * The keyPressed signal is emitted when a key is pressed, and a
   * character is entered. Unlike \link
   * WAbstractArea::keyWentDown\endlink, it is emitted only for key
   * presses that result in a character being entered, and thus not
   * for modifier keys or keyboard navigation keys.
   *
   * \sa WAbstractArea::keyWentDown
   */
  EventSignal<WKeyEvent>& keyPressed;
    
  /*! \brief Event signal emitted when a keyboard key is released.
   *
   * This is the counter-part of the \link
   * WAbstractArea::keyWentDown\endlink event. Every key-down has its
   * corresponding key-up.
   *
   * \sa WAbstractArea::keyWentDown
   */
  EventSignal<WKeyEvent>& keyWentUp;

  /*! \brief Event signal emitted when enter was pressed.
   *
   * This signal is emitted when the Enter or Return key was pressed.
   *
   * \sa keyPressed, Key_Enter
   */
  EventSignal<void>& enterPressed;

  /*! \brief Event signal emitted when escape was pressed.
   *
   * This signal is emitted when the Escape key was pressed.
   *
   * \sa keyPressed, Key_Escape
   */
  EventSignal<void>& escapePressed;

  /*! \brief Event signal emitted when a mouse key was clicked on this
   *         widget.
   *
   * The event details contains information such as the \link
   * WMouseEvent::button button\endlink, optional \link
   * WMouseEvent::modifiers() keyboard modifiers\endlink, and mouse
   * coordinates relative to the \link WMouseEvent::widget()
   * widget\endlink, the window \link WMouseEvent::window()
   * window\endlink, or the \link WMouseEvent::document()
   * document\endlink.
   *
   * @note When JavaScript is disabled, the event details contain
   * invalid information.
   */
  EventSignal<WMouseEvent>& clicked;

  /*! \brief Event signal emitted when a mouse key was double clicked
   *         on this widget.
   *
   * The event details contains information such as the \link
   * WMouseEvent::button button\endlink, optional \link
   * WMouseEvent::modifiers() keyboard modifiers\endlink, and mouse
   * coordinates relative to the \link WMouseEvent::widget()
   * widget\endlink, the window \link WMouseEvent::window()
   * window\endlink, or the \link WMouseEvent::document()
   * document\endlink.
   *
   * @note When JavaScript is disabled, the signal will never fire.
   */
  EventSignal<WMouseEvent>& doubleClicked;

  /*! \brief Event signal emitted when a mouse key was pushed down on this
   *         widget.
   *
   * The event details contains information such as the \link
   * WMouseEvent::button button\endlink, optional \link
   * WMouseEvent::modifiers() keyboard modifiers\endlink, and mouse
   * coordinates relative to the \link WMouseEvent::widget()
   * widget\endlink, the window \link WMouseEvent::window()
   * window\endlink, or the \link WMouseEvent::document()
   * document\endlink.
   *
   * @note When JavaScript is disabled, the signal will never fire.
   */
  EventSignal<WMouseEvent>& mouseWentDown;

  /*! \brief Event signal emitted when a mouse key was released on this
   *         widget.
   *
   * The event details contains information such as the \link
   * WMouseEvent::button button\endlink, optional \link
   * WMouseEvent::modifiers() keyboard modifiers\endlink, and mouse
   * coordinates relative to the \link WMouseEvent::widget()
   * widget\endlink, the window \link WMouseEvent::window()
   * window\endlink, or the \link WMouseEvent::document()
   * document\endlink.
   *
   * @note When JavaScript is disabled, the signal will never fire.
   */
  EventSignal<WMouseEvent>& mouseWentUp;

  /*! \brief Event signal emitted when the mouse went out of this widget.
   *
   * @note When JavaScript is disabled, the signal will never fire.
   */
  EventSignal<WMouseEvent>& mouseWentOut;
    
  /*! \brief Event signal emitted when the mouse entered this widget.
   *
   * @note When JavaScript is disabled, the signal will never fire.
   */
  EventSignal<WMouseEvent>& mouseWentOver;

  /*! \brief Event signal emitted when the mouse moved over this widget.
   *
   * @note When JavaScript is disabled, the signal will never fire.
   */
  EventSignal<WMouseEvent>& mouseMoved;

private:
  struct AnchorImpl {
    std::string   ref_;
    WResource    *resource_;
    AnchorTarget  target_;
    WString       altText_;
  };

  bool              hole_;
  AnchorImpl       *anchor_;

  void createAnchorImpl();
  void resourceChanged();

protected:
  WAbstractArea();

  virtual void updateDom(DomElement& element, bool all);
  void repaint();

private:
  WInteractWidget *impl();

  void setImage(WImage *image);
  static WAbstractArea *areaForImpl(WWidget *w);

  friend class WImage;
  friend class Impl::AreaWidget;
};

}

#endif // WABSTRACT_AREA_H_
