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

#include <Wt/WGlobal>
#include <string>
#include <vector>

namespace Wt {

class WebRequest;
class WObject;
class WString;

template<class E> class EventSignal;

class WT_API JavaScriptEvent {
public:
  // for mouse events:
  int  clientX, clientY;
  int  documentX, documentY;
  int  screenX, screenY;
  int  widgetX, widgetY;
  int  dragDX, dragDY;

  // for key events or mouse event modifiers
  bool right;
  int  keyCode, charCode;
  WFlags<KeyboardModifier> modifiers;

  // for scroll events
  int  scrollX, scrollY, viewportWidth, viewportHeight;

  // event type
  std::string type;

  // target id
  std::string tid;

  std::string response;

  std::vector<std::string> userEventArgs;

  void get(const WebRequest& request, const std::string& se);

  JavaScriptEvent();
};

#ifdef WT_TARGET_JAVA
/*! \class WAbstractEvent Wt/WEvent Wt/WEvent
 *  \brief Internal class WAbstractEvent.
 */
class WAbstractEvent
{
public:
  virtual WAbstractEvent *createFromJSEvent(const JavaScriptEvent& jsEvent) = 0;
};
#endif // WT_TARGET_JAVA

/*! \class WMouseEvent Wt/WEvent Wt/WEvent
 *  \brief A class providing details for a mouse event.
 *
 * \sa WInteractWidget::clicked(), WInteractWidget::doubleClicked(),
 *     WInteractWidget::mouseWentDown(), WInteractWidget::mouseWentUp(),
 *     WInteractWidget::mouseWentOver(), WInteractWidget::mouseMoved()
 *
 * \ingroup signalslot
 */
class WT_API WMouseEvent
#ifdef WT_TARGET_JAVA
                         : public WAbstractEvent
#endif // WT_TARGET_JAVA
{
public:
  /*! \brief Default constructor
   */
  WMouseEvent();

  /*! \brief Enumeration for the mouse button.
   */
  enum Button { LeftButton,    //!< Left button
		MiddleButton,  //!< Middle button
		RightButton    //!< Right button
  };

  /*! \brief A mouse coordinate.
   */
  struct Coordinates {
    int x; //!< X coordinate
    int y; //!< Y coordinate

    /*! \brief Constructor.
     */
    Coordinates(int x_, int y_)
      : x(x_), y(y_) { }
  };

  /*! \brief Returns the button.
   */
  Button button() const { return jsEvent_.right ? RightButton : LeftButton; }

  /*! \brief Returns keyboard modifiers.
   *
   * The result is a logical OR of \link Wt::KeyboardModifier
   * KeyboardModifier\endlink flags.
   */
  WFlags<KeyboardModifier> modifiers() const { return jsEvent_.modifiers; }

  /*! \brief Returns the mouse position relative to the document.
   */
  Coordinates document() const
  { return Coordinates(jsEvent_.documentX, jsEvent_.documentY); }

  /*! \brief Returns the mouse position relative to the window.
   *
   * This differs from documentX() only through scrolling
   * through the document.
   */
  Coordinates window() const
  { return Coordinates(jsEvent_.clientX, jsEvent_.clientY); }

  /*! \brief Returns the mouse position relative to the screen.
   */
  Coordinates screen() const
  { return Coordinates(jsEvent_.screenX, jsEvent_.screenY); }

  /*! \brief Returns the mouse position relative to the widget.
   */
  Coordinates widget() const
  { return Coordinates(jsEvent_.widgetX, jsEvent_.widgetY); }

  /*! \brief Returns the distance over which the mouse has been dragged.
   *
   * This is only defined for a WInteractWidget::mouseWentUp() event.
   */
  Coordinates dragDelta() const
  { return Coordinates(jsEvent_.dragDX, jsEvent_.dragDY); }

#ifndef WT_DEPRECATED_3_0_0
  /*! \brief Returns whether the alt key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool altKey() const { return (jsEvent_.modifiers & AltModifier) != 0; }

  /*! \brief Returns whether the meta key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool metaKey() const { return (jsEvent_.modifiers & MetaModifier) != 0; }

  /*! \brief Returns whether the control key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool ctrlKey() const { return (jsEvent_.modifiers & ControlModifier) != 0; }

  /*! \brief Returns whether the shift key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool shiftKey() const { return (jsEvent_.modifiers & ShiftModifier) != 0; }
#endif // WT_DEPRECATED_3_0_0

#ifdef WT_TARGET_JAVA
  virtual WAbstractEvent *createFromJSEvent(const JavaScriptEvent& jsEvent)
  {
    return new WMouseEvent(jsEvent);
  }

  static WMouseEvent templateEvent;
#endif // WT_TARGET_JAVA

  WMouseEvent(const JavaScriptEvent& jsEvent);

protected:
  JavaScriptEvent jsEvent_;
};

/*! \class WKeyEvent Wt/WEvent Wt/WEvent
 *  \brief A class providing details for a keyboard event.
 *
 * A key event is associated with the WInteractWidget::keyWentDown(),
 * WInteractWidget::keyWentUp() and WInteractWidget::keyPressed()
 * signals.
 *
 * \ingroup signalslot
 */
class WT_API WKeyEvent
#ifdef WT_TARGET_JAVA
                         : public WAbstractEvent
#endif // WT_TARGET_JAVA
{
public:
  /*! \brief Default constructor
   */
  WKeyEvent();

  /*! \brief Returns the key code key that was pressed or released.
   *
   * The key code corresponds to the actual key on the keyboard,
   * rather than the generated character.
   *
   * All three types of key events provide this information.
   *
   * \sa modifiers(), charCode()
   */
  Key key() const;

  /*! \brief Returns keyboard modifiers.
   *
   * The result is a logical OR of \link Wt::KeyboardModifier
   * KeyboardModifier\endlink flags.
   *
   * All three types of key events provide this information.
   *
   * \sa key(), charCode()
   */
  WFlags<KeyboardModifier> modifiers() const { return jsEvent_.modifiers; }

  /*! \brief Returns the unicode character code.
   *
   * This is only defined for a \link WInteractWidget::keyPressed
   * keyPressed \endlink event, and returns the unicode character code
   * of a character that is entered.
   *
   * For the \link WInteractWidget::keyWentDown keyWentDown \endlink
   * and \link WInteractWidget::keyWentUp keyWentUp \endlink events,
   * '0' is returned.
   *
   * The charCode() may be different from key(). For example, a \link
   * Wt::Key_M Key_M\endlink key may correspond to 'm' or 'M'
   * character, depending on whether the shift key is pressed
   * simultaneously.
   *
   * \sa key(), text()
   */
  int charCode() const;

  /*! \brief The (unicode) text that this key generated.
   *
   * This is only defined for a \link WInteractWidget::keyPressed
   * keyPressed \endlink event, and returns a string that holds
   * exactly one unicode character, which corresponds to charCode().
   *
   * For the \link WInteractWidget::keyWentDown keyWentDown \endlink
   * and \link WInteractWidget::keyWentUp keyWentUp \endlink events,
   * an empty string is returned.
   *
   * \sa charCode()
   */
  WT_USTRING text() const;

#ifndef WT_DEPRECATED_3_0_0
  /*! \brief Returns the raw key code (<b>deprecated</b>).
   *
   * \deprecated The value returned is somewhat browser-specific, and
   * it is therefore recommended to use the key() method instead.
   *
   * \sa key()
   */
  int keyCode() const { return jsEvent_.keyCode; }

  /*! \brief Returns whether the alt key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool altKey() const { return (jsEvent_.modifiers & AltModifier) != 0; }

  /*! \brief Returns whether the meta key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool metaKey() const { return (jsEvent_.modifiers & MetaModifier) != 0; }

  /*! \brief Returns whether the control key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool ctrlKey() const { return (jsEvent_.modifiers & ControlModifier) != 0; }

  /*! \brief Returns whether the shift key is pressed (<b>deprecated</b>).
   *
   * \deprecated Use modifiers() instead.
   */
  bool shiftKey() const { return (jsEvent_.modifiers & ShiftModifier) != 0; }
#endif // WT_DEPRECATED_3_0_0

#ifdef WT_TARGET_JAVA
  virtual WAbstractEvent *createFromJSEvent(const JavaScriptEvent& jsEvent)
  {
    return new WKeyEvent(jsEvent);
  }

  static WKeyEvent templateEvent;
#endif // WT_TARGET_JAVA

  WKeyEvent(const JavaScriptEvent& jsEvent);

private:
  JavaScriptEvent jsEvent_;
};

/*! \class WDropEvent Wt/WEvent Wt/WEvent
 *  \brief A class providing details for a drop event.
 *
 * \sa WWidget::dropEvent(WDropEvent)
 *
 * \ingroup signalslot
 */
class WT_API WDropEvent
{
public:
  /*! \brief Constructor.
   */
  WDropEvent(WObject *source, const std::string& mimeType,
	     const WMouseEvent& mouseEvent);

  /*! \brief Returns the source of the drag&drop operation.
   *
   * The source is the widget that was set draggable using
   * WInteractWidget::setDraggable().
   */
  WObject *source() const { return dropSource_; }

  /*! \brief Returns the mime type of this drop event.
   */
  const std::string& mimeType() const { return dropMimeType_; }

  /*! \brief Returns the original mouse event.
   */
  const WMouseEvent& mouseEvent() const { return mouseEvent_; }

private:
  WObject            *dropSource_;
  std::string         dropMimeType_;
  const WMouseEvent&  mouseEvent_;
};

/*! \class WScrollEvent Wt/WEvent Wt/WEvent
 *  \brief A class providing details for a scroll event.
 *
 * \sa WContainerWidget::scrolled()
 *
 * \ingroup signalslot
 */
class WT_API WScrollEvent
#ifdef WT_TARGET_JAVA
                         : public WAbstractEvent
#endif // WT_TARGET_JAVA
{
public:
  /*! \brief Default constructor
   */
  WScrollEvent();

  /*! \brief Returns the current horizontal scroll position.
   *
   * \sa scrollY(), viewportWidth()
   */
  int scrollX() const { return jsEvent_.scrollX; }

  /*! \brief Returns the current vertical scroll position.
   *
   * \sa scrollX(), viewportHeight()
   */
  int scrollY() const { return jsEvent_.scrollY; }

  /*! \brief Returns the current horizontal viewport width.
   *
   * Returns the current viewport width.
   *
   * \sa viewportHeight(), scrollX()
   */
  int viewportWidth() const { return jsEvent_.viewportWidth; }

  /*! \brief Returns the current horizontal viewport height.
   *
   * Returns the current viewport height.
   *
   * \sa viewportWidth(), scrollY()
   */
  int viewportHeight() const { return jsEvent_.viewportHeight; }

#ifdef WT_TARGET_JAVA
  virtual WAbstractEvent *createFromJSEvent(const JavaScriptEvent& jsEvent)
  {
    return new WScrollEvent(jsEvent);
  }

  static WScrollEvent templateEvent;
#endif // WT_TARGET_JAVA

private:
  JavaScriptEvent jsEvent_;

  WScrollEvent(const JavaScriptEvent& jsEvent);

  friend class EventSignal<WScrollEvent>;
};

}

#endif // WEVENT_H_
