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

#include <WResource>
#include <WLength>
#include <WBorder>
#include <WValidator>
#include <WSignal>

#include <vector>

/*! \file WWidget */

namespace Wt {

class WContainerWidget;
class WCssDecorationStyle;
class WDropEvent;
class WLayout;
class WLayoutItemImpl;
class WLayoutItem;
class WString;
class WWebWidget;
class DomElement;

/*! \brief Enumeration that indicates direction.
 */
enum Orientation { Horizontal, //!< Horizontal
		   Vertical    //!< Vertical
};

/*! \brief A standard button for the message box.
 *
 * Multiple buttons may be specified by logically or'ing these values
 * together, e.g.
 * \code
 * Ok | Cancel
 * \endcode
 */
enum StandardButton {
  NoButton = 0x00,  //!< No button
  Ok = 0x01,        //!< An OK button.
  Cancel = 0x02,    //!< A Cancel button.
  Yes = 0x04,       //!< A Yes button.
  No = 0x08,        //!< A No button.
  Abort = 0x10,     //!< An Abort button.
  Retry = 0x20,     //!< A Retry button.
  Ignore = 0x40,    //!< An Ignore button.
  YesAll = 0x80,    //!< A Yes-to-All button.
  NoAll = 0x100     //!< A No-to-All button.
};

/*! \brief A standard icon for the message box.
 */
enum Icon {
  NoIcon = 0,       //!< No icon
  Information = 1,  //!< An information icon <i>(not implemented)</i>
  Warning = 2,      //!< An warning icon <i>(not implemented)</i>
  Critical = 3,     //!< An critical icon <i>(not implemented)</i>
  Question = 4      //!< An question icon <i>(not implemented)</i>
};

/*! \brief Enumeration that indicates how items may be selected.
 */
enum SelectionMode { NoSelection = 0,      //!< No selections
		     SingleSelection = 1,  //!< Single selection only
		     ExtendedSelection = 3 //!< Multiple selection
};

/*! \brief Enumeration that indicates what is being selected.
 */
enum SelectionBehavior { SelectItems = 0,    //!< Select single items 
			 SelectRows = 1      //!< Select only rows
			 /*, SelectColumns */
};

/*! \brief Enumeration that indicates what is the selection unit.
 *
 * @deprecated Use SelectionBehavior instead.
 */
enum SelectionUnit { CellSelection = 0,    //!< Select inividual cells 
		     RowSelection = 1      //!< Select whole rows
};

/*! \class WWidget WWidget WWidget
 *  \brief A %WWidget is the abstract base class for any %Wt widget.
 *
 * The user-interface is organized in a tree structure, in which all nodes
 * are WWidgets. When the parent widget is deleted, all children are deleted
 * likewise. All WWidgets, except for the application's root widget
 * have a parent, which is usually a WContainerWidget.
 *
 * %WWidget is abstract and cannot be instantiated. Implementations
 * either from WWebWidget (for basic widgets with a direct HTML
 * counter-part) or WCompositeWidget (for anything else). To add a
 * WWebWidget to a parent WContainerWidget, either specify the parent
 * in the constructor, or add the widget to the parent using
 * WContainerWidget::addWidget(WWidget *).
 *
 * A %WWidget provides methods to manage its decorative style, and its
 * layout with respect to the parent widget.
 */
class WT_API WWidget : public WResource {
public:
  /*! \brief Construct a widget with a given parent.
   *
   * Constructs a WWidget. If a parent WObject is specified it will add this
   * object to the parent's list and gets deleted when the parent is deleted.
   * If this widget is a WWebWidget and the parent is a WContainerWidget,
   * it will visually add this widget to its children.
   */
  WWidget(WContainerWidget* parent = 0);

  /*! \brief Delete a widget.
   *
   * Deletes a WWidget, and all child widgets. If necessary,
   * the WWidget is removed from its parent.
   */
  virtual ~WWidget();

  /*! \brief Return the parent widget.
   */
  WWidget *parent() const { return parent_; }

  /*! \brief Layout mechanism for this widget.
   *
   * The layout mechanism for the WWidget.
   * \sa setPositionScheme(PositionScheme scheme)
   */
  enum PositionScheme {
    /*! \brief Static position scheme.
     * 
     *  The widget is layed-out with other \link WWidget::Static
     *  Static \endlink and \link WWidget::Relative Relative \endlink
     *  sibling widgets, one after another.
     *
     *  Inline widgets are layed out in horizontal lines (like text),
     *  wrapping around at the end of the line to continue on the next
     *  line. Stacked widgets are stacked vertically.
     *
     *  Static widgets may also float to the left or right border,
     *  using setFloatSide().
     */
    Static,
    /*! \brief Relative position scheme.
     *
     *  The widget is first layed out according to Static layout
     *  rules, but after layout, the widget may be offset relative to
     *  where it would be in a static layout, using setOffsets().
     *
     *  Another common use of a Relative position scheme (even with no
     *  specified offsets) is to provide a new reference coordinate
     *  system for Absolutely positioned widgets.
     */
    Relative,
    /*! \brief Absolute position scheme.
     *
     *  The widget is positioned at an absolute position
     *  with respect to the nearest ancestor widget that is either:
     *  <ul>
     *    <li> a WTableCell </li>
     *    <li> or has a position scheme that is \link WWidget::Relative
     *  Relative\endlink or \link WWidget::Absolute Absolute\endlink. </li>
     *  </ul>
     */
    Absolute,
    /*! \brief Fixed position scheme.
     *
     *  The widget is positioned at fixed position with respect to
     *  the browser's view-pane.
     */
    Fixed
  };

  /*! \brief Enumeration that designates a relative location.
   *
   * Values of CenterX, CenterY, and CenterXY are only valid for
   * WCssDecorationStyle::setBackgroundImage()
   *
   * \sa setOffsets(WLength x, int sides), setFloatSide(Side s),
   *     setClearSides(int sides)
   * \sa WCssDecorationStyle::setBackgroundImage()
   */
  enum Side { None = 0x0,                 //!< No side
	      Top = 0x1,                  //!< Top side
	      Bottom = 0x2,               //!< Bottom side
	      Left = 0x4,                 //!< Left side
	      Right = 0x8,                //!< Right side
	      CenterX = 0x10,             //!< Center horiziontally
	      CenterY = 0x20,             //!< Center vertically
	      CenterXY = (0x10 | 0x20),   //!< (CenterX | CenterY)
              Verticals = (0x4 | 0x8),    //!< (Left | Right)
              Horizontals = (0x1 | 0x8),  //!< (Top | Bottom)
	      All = (Top | Bottom | Left | Right) //!< All sides
  };

  /*! \brief Vertical alignment of this widget.
   *
   * This only applies to inline widgets, and determines how to position
   * itself on the current line, with respect to sibling inline widgets.
   *
   * \sa setVerticalAlignment(VerticalAlignment, WLength)
   * \sa WTableCell::setContentAlignment()
   */
  enum VerticalAlignment { AlignBaseline=0x0, //!< Align at baseline
  			   AlignSub=0x10,     //!< Align below the baseline
			   AlignSuper=0x20,   //!< Align above the baseline
			   AlignTop=0x30,     //!< Align top of widget
			   AlignTextTop=0x40, //!< Align text top ?
			   AlignMiddle=0x50,  //!< Align middle of widget
			   AlignBottom=0x60,  //!< Align bottom of widget
			   AlignTextBottom=0x70, //!< Align text bottom ?
			   AlignLength=0x80   //!< Specific length offset ?
			 };

  /*! \brief The horizontal alignment of child widgets.
   *
   * \sa WContainerWidget::setContentAlignment()
   */
  enum HorizontalAlignment {
    AlignLeft=0x1,   //!< Align children to the left
    AlignRight=0x2,  //!< Align children to the right
    AlignCenter=0x3, //!< Align children to the center
    AlignJustify=0x4 //!< Justify children left and right
  };

  /*! \brief Set the widget position scheme.
   *
   * Establishes how the widget must be layed-out relative to its
   * siblings. The default position scheme is Static.
   *
   * \sa PositionScheme, positionScheme()
   */
  virtual void setPositionScheme(PositionScheme scheme) = 0;

  /*! \brief Get the widget position scheme.
   *
   * \sa PositionScheme, setPositionScheme(PositionScheme)
   */
  virtual PositionScheme positionScheme() const = 0;

  /*! \brief Apply offsets to a widget.
   *
   * <i>sides</i> may be a logical concatenation of Left, Right, Top,
   * and Bottom.
   *
   * This applies only to widgets that have a position scheme that is
   * \link WWidget::Relative Relative\endlink, \link WWidget::Absolute
   * Absolute\endlink, or \link WWidget::Fixed Fixed\endlink, and has
   * a slightly different meaning for these three cases.
   *
   * For a relatively positioned widget, an offset applies relative to
   * the position the widget would have when layed-out using a \link
   * WWidget::Static Static\endlink position scheme. The widget may be
   * shifted to the left or right by specifying an offset to the \link
   * WWidget::Left Left\endlink or \link WWidget::Right
   * Right\endlink). The widget may be shifted vertically, by
   * specifying an offset for the \link WWidget::AlignTop Top\endlink
   * or \link WWidget::Bottom Bottom\endlink.
   *
   * For an absolutely positioned widget, an offset specifies a
   * distance of the corresponding side of the widget with respect to
   * the corresponding side of the reference parent widget. Thus,
   * setting all offsets to 0 result in a widget that spans the entire
   * reference widget. The reference parent widget is the first
   * ancestor widget that is a table cell, or a widget with a relative,
   * absolute or fixed position scheme.
   *
   * For an absolutely positioned widget, an offset specifies a
   * distance of the corresponding side of the widget with respect to
   * the browser window, regardless of scrolling. Thus, setting all
   * offsets to 0 result in a widget that spans the entire browser
   * window.
   *
   * <i>Note: this method replaces the now deprecated setOffset(Side
   * side, WLength offset) method.</i>
   *
   * \sa offset(Side) const
   */
  virtual void setOffsets(WLength offset, int sides = All) = 0;

  /* \brief Apply offsets to a widget (deprecated).
   *
   * <i>This method has been deprecated: use setOffsets(WLength, int)
   * instead.</i>
   *
   * \sa setOffsets(WLength, int)
   */
  void setOffset(int sides, WLength offset);

  /*! \brief Retrieve the offset of the widget.
   *
   * \sa setOffsets(WLength, int)
   */
  virtual WLength offset(Side side) const = 0;

  /*! \brief Resize the widget.
   *
   * Specify a new size for this widget, by specifying width and height.
   * By default a widget has automatic width and height, see WLength::isAuto().
   *
   * \sa width(), height()
   */
  virtual void resize(WLength width, WLength height) = 0;

  /*! \brief Get the widget width.
   *
   * Return the width set for this widget. This is not a calculated width,
   * based on layout, but the width as specified with
   * resize(WLength width, WLength height).
   *
   * \sa resize(WLength width, WLength height), height()
   */
  virtual WLength width() const = 0;

  /*! \brief Get the widget height.
   *
   * Return the height set for this widget. This is not a calculated height,
   * based on layout, but the height as specified previously with
   * resize(WLength width, WLength height).
   *
   * \sa resize(WLength width, WLength height), width()
   */
  virtual WLength height() const = 0;

  /*! \brief Set a minimum size.
   *
   * Specify a minimum size for this widget.
   *
   * \sa resize(), minimumWidth(), minimumHeight()
   */
  virtual void setMinimumSize(WLength width, WLength height) = 0;

  /*! \brief Get the minimum width.
   *
   * Return the minimum width set for this widget with setMinimumSize().
   *
   * \sa setMinimumSize(), minimumHeight()
   */
  virtual WLength minimumWidth() const = 0;

  /*! \brief Get the minimum height.
   *
   * Return the minmum height set for this widget with setMinimumSize().
   *
   * \sa setMinimumSize(), minimumWidth()
   */
  virtual WLength minimumHeight() const = 0;

  /*! \brief Set a maximum size.
   *
   * Specify a minimum size for this widget.
   *
   * \sa resize(), maximumWidth(), maximumHeight()
   */
  virtual void setMaximumSize(WLength width, WLength height) = 0;

  /*! \brief Get the maximum width.
   *
   * Return the maximum width set for this widget with setMaximumSize().
   *
   * \sa setMaximumSize(), maximumHeight()
   */
  virtual WLength maximumWidth() const = 0;

  /*! \brief Get the maximum height.
   *
   * Return the minmum height set for this widget with setMaximumSize().
   *
   * \sa setMaximumSize(), maximumWidth()
   */
  virtual WLength maximumHeight() const = 0;

  /*! \brief Specify a side to which the WWidget must float.
   *
   * This only applies to WWidgets with a \link WWidget::Static Static
   * \endlink positionScheme().
   *
   * It specifies if the WWidget must be positioned on one of the
   * sides of the parent widget, at the current line. A typical use is
   * to position images within text. Valid values for Side or \link
   * WWidget::None None \endlink, \link WWidget::Left Left \endlink or
   * \link WWidget::Right Right \endlink.
   */
  virtual void setFloatSide(Side s) = 0;

  /*! \brief Return the float side.
   *
   * \sa setFloatSide(Side)
   */
  virtual Side floatSide() const = 0;

  /*! \brief Set the sides that should remain empty.
   */
  virtual void setClearSides(int sides) = 0;

  /*! \brief Get the sides that should remain empty.
   */
  virtual int clearSides() const = 0;

  /*! \brief Set margins around the widget.
   *
   * Setting margin has the effect of adding a distance between the widget
   * and surrounding widgets. The default margin (with an automatic length)
   * is zero.
   *
   * Use any combination of \link WWidget::Left Left \endlink,
   * \link WWidget::Right Right \endlink,
   * \link WWidget::Bottom Bottom \endlink,
   * or \link WWidget::Top Top \endlink.
   *
   * \sa WWidget::margin(Side side);
   */
  virtual void setMargin(WLength margin, int sides = All) = 0;

  /*! \brief Get the margin set for that side.
   *
   * \sa WWidget::setMargin(WLength margin, int sides);
   */
  virtual WLength margin(Side side) const = 0;

  /*! \brief Set whether the widget must be hidden.
   *
   * Hide or show the widget (including all its descendant widgets).
   * setHidden(false) will show this widget and all child widgets that
   * are not hidden.
   *
   * \sa hide(), show()
   */
  virtual void setHidden(bool) = 0;

  /*! \brief Return whether this widget is set hidden.
   *
   * A widget that is not hidden may still be not visible when one
   * of its ancestor widgets are hidden.
   *
   * \sa setHidden()
   */
  virtual bool isHidden() const = 0;

  /*! \brief Set whether this widget is overlayed on the parent widget.
   *
   * This option only applies to widgets with a \link
   * WWidget::Absolute Absolute \endlink or \link WWidget::Fixed Fixed
   * \endlink positionScheme().
   *
   * A widget that isPopup() will be rendered on top of the parent widget.
   */
  virtual void setPopup(bool) = 0;

  /*! \brief Returns whether this WWidget is overlayed.
   *
   * \sa setPopup(bool)
   */
  virtual bool isPopup() const = 0;

  /*! \brief Set whether this widget is inline or stacked.
   *
   * This option changes whether this widget must be rendered in-line
   * with sibling widgets wrapping at the right edge of the parent
   * container (like text), or whether this widget must be stacked
   * vertically with sibling widgets. Depending on the WWidget type,
   * the default value is inline (such as for example for WText, or
   * WPushButton), or stacked (such as for example for WTable).
   */
  virtual void setInline(bool) = 0;

  /*! \brief Returns whether this widget is inline or stacked.
   *
   * \sa setInline(bool)
   */
  virtual bool isInline() const = 0;

  /*! \brief Access the decoration style of this widget.
   *
   * This groups all decorative aspects of the widget, which do not affect
   * the widget layout (except for the border properties which change the
   * total size of the widget when adding a non-zero-width border).
   */
  virtual WCssDecorationStyle& decorationStyle() = 0;

  /*! \brief Specify that a particular style class must be applied
   *         to this WWidget.
   *
   * To remove the style class, set an empty string as style class.
   * 
   * \sa WApplication::styleSheet()
   */
  virtual void setStyleClass(const WString& styleClass) = 0;

  void setStyleClass(const char *styleClass);

  /*! \brief Returns the style class for this WWidget.
   *
   * \sa setStyleClass(const WString&)
   */
  virtual WString styleClass() const = 0;

  /*! \brief Set the vertical alignment of this (inline) WWidget.
   *
   * This only applies to inline widgets, and determines how to position
   * itself on the current line, with respect to sibling inline widgets.
   */
  virtual void setVerticalAlignment(VerticalAlignment alignment,
				    WLength length = WLength()) = 0;

  /*! \brief Get the vertical alignment of this WWidget.
   *
   * \sa WWidget::setVerticalAlignment()
   */
  virtual VerticalAlignment verticalAlignment() const = 0;

  /*! \brief Get the a fixed vertical alignment with respect to the baseline
   *             of this WWidget.
   *
   * \sa WWidget::setVerticalAlignment()
   */
  virtual WLength verticalAlignmentLength() const = 0;

  virtual WWebWidget *webWidget() = 0;

  /*! \brief Set the tooltip for the widget.
   *
   * The tooltip is displayed when the cursor rests above the widget.
   */
  virtual void setToolTip(const WString& text) = 0;

  /*! \brief Get the tooltip text.
   */
  virtual WString toolTip() const = 0;

  /*! \brief Refresh the widget.
   *
   * The refresh method is invoked when the locale is changed using
   * WApplication::setLocale() or when the user hit the refresh button.
   *
   * The widget must actualize its contents in response.
   */
  virtual void refresh() = 0;

  /*! \brief A JavaScript expression that returns the corresponding DOM node.
   */
  std::string jsRef() const;

  /*! \brief Set an attribute value.
   *
   * Associate an extra attribute with this widget, with the given value.
   * This is only useful when processing dom nodes associated with widgets
   * in custom JavaScript code.
   *
   * \sa JSlot, WApplication::doJavaScript()
   */
  virtual void setAttributeValue(const std::string& name,
				 const WString& value) = 0;

  /*! \brief Short hand for WString::tr()
   *
   * Create a message with the given key.
   */
  static WString tr(const char *key);

  /*! \brief Load content just before the widget's content is rendered.
   *
   * As soon as a widget is inserted into the widget hierarchy, it is
   * rendered. Visible widgets are rendered immediately, and invisible
   * widgets in the back-ground. This method is called when the widget
   * is directly or indirectly inserted into the widget tree.
   *
   * The default implementation simply propagates the load signal to its
   * children. You may want to override this method to load resource-intensive
   * content only when the widget is loaded into the browser.
   */
  virtual void load() = 0;

  /*! \brief Return if this widget has been loaded.
   *
   * \sa load()
   */
  virtual bool loaded() const = 0;

  /*! \brief Set a mime type to be accepted for dropping.
   *
   * You may specify a style class that is applied to the widget when the
   * specified mimetype hovers on top of it.
   *
   * \sa dropEvent, setDraggable, stopAcceptDrops
   */
  virtual void acceptDrops(const std::string& mimeType,
			   const WString& hoverStyleClass = WString());

  /*! \brief No longer accept a mime type for dropping.
   *
   * \sa acceptDrops
   */
  virtual void stopAcceptDrops(const std::string& mimeType);

  /*! \brief Set the CSS Id.
   *
   * Sets a custom Id. Note that the Id must be unique across the whole
   * widget tree, can only be set right after construction and cannot
   * be changed.
   *
   * \sa WObject::id()
   */
  virtual void setId(const std::string& id) = 0;

  std::string createJavaScript(std::string& js, const std::string& insertJS);

public slots:

  /*! \brief Hide this WWidget.
   *
   * \sa setHidden(bool)
   */
  void hide();

  /*! \brief Show this WWidget.
   *
   * \sa setHidden(bool)
   */
  void show();

protected:
  bool     resourceTriggerUpdate_;

  /*! \brief Handle a drop event.
   *
   * Reimplement this method to handle a drop events for mime types you
   * declared to accept using setAcceptDrops.
   *
   * The default implementation simply completes the drag and drop operation
   * as if nothing happened.
   *
   * \sa setAcceptDrops, setDraggable
   */
  virtual void dropEvent(WDropEvent dropEvent);
  void getDrop(const std::string sourceId, const std::string mimeType);

  virtual void addChild(WWidget *child) = 0;
  virtual void removeChild(WWidget *child) = 0;
  virtual void addNewSibling(WWidget *sibling) = 0;
  virtual void setHideWithOffsets(bool how = true) = 0;

  virtual void setParent(WWidget *parent);

  virtual bool isVisible() const = 0;
  virtual bool isStubbed() const = 0;

  WWidget *adam();

  /*
   * Implement the resource methods.
   */
  virtual const std::string resourceMimeType() const;
  virtual void setArguments(const ArgumentMap& arguments);
  virtual bool streamResourceData(std::ostream& stream,
				  const ArgumentMap& arguments);
  virtual void resourceHTML(std::ostream& out);

  virtual void setLayout(WLayout *layout);

private:
  WWidget *parent_;
  bool     wasHidden_;

  virtual WLayoutItemImpl  *createLayoutItemImpl(WLayoutItem *layout);
  virtual WLayout          *layout() const;

  void     undoHideShow();

  friend class WebRenderer;

  friend class WContainerWidget;
  friend class WCompositeWidget;
  friend class WScrollArea;
  friend class WWebWidget;
  friend class WLayout;
  friend class WWidgetItem;
};

}

#endif // WWIDGET_H_
