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

#include <string>
#include <vector>

#include <Wt/WGlobal>
#include <Wt/WLayoutItem>
#include <Wt/WObject>

namespace Wt {

class WWidgetItem;
class WLayoutItemImpl;

/*! \class WLayout Wt/WLayout Wt/WLayout
 *  \brief An abstract base class for layout managers.
 *
 * This class is the abstract base class for any layout manager. A layout
 * manager is associated with a container widget, and manages the layout of
 * children inside the whole space available to the container widget.
 *
 * \if cpp
 * Layout managers may be used with WContainerWidget and
 * Ext::Container container widgets. A suitable implementation for all
 * layout classes is not yet available for both containers, and thus
 * you need to refer to the documentation of a layout manager to
 * see if it is applicable to your situation.
 * \endif
 *
 * The implementation of the layout manager depends on the container widget
 * to which it is set, and is therefore deferred to WLayoutImpl.
 *
 * A layout never assumes ownership of contained items, instead these
 * are owned by the parent widget to which the layout is applied.
 *
 * \note When applying a layout manager to a WContainerWidget, you may
 * not define any padding for the container widget. Instead, use
 * setContentsMargins().
 */
class WT_API WLayout : public WLayoutItem, public WObject
{
public:
  /*! \brief Destructor.
   *
   * This will delete the layout (and nested layouts), but not the
   * contained widgets.
   */
  virtual ~WLayout();

  /*! \brief Adds a layout <i>item</i>.
   *
   * The item may be a widget or nested layout.
   *
   * How the item is layed out with respect to siblings is
   * implementation specific to the layout manager. In some cases, a
   * layout manager will overload this method with extra arguments
   * that specify layout options.
   *
   * \sa removeItem(WLayoutItem *), addWidget(WWidget *)
   */
  virtual void addItem(WLayoutItem *item) = 0;

  /*! \brief Adds the given <i>widget</i> to the layout.
   *
   * This method wraps the widget in a WWidgetItem and calls
   * addItem(WLayoutItem *).
   *
   * How the widget is layed out with respect to siblings is
   * implementation specific to the layout manager. In some cases, a
   * layout manager will overload this method with extra arguments
   * that specify layout options.
   *
   * \sa removeWidget(WWidget *), addItem(WLayoutItem *)
   */
  void addWidget(WWidget *widget);

  /*! \brief Removes a layout <i>item</i> (widget or nested layout).
   *
   * \sa addItem(WLayoutItem *), removeWidget(WWidget *)
   */
  virtual void removeItem(WLayoutItem *item) = 0;

  /*! \brief Removes the given <i>widget</i> from the layout.
   *
   * This method finds the corresponding WWidgetItem and calls
   * removeItem(WLayoutItem *). The widget itself is not destroyed.
   *
   * Returns \c true if succesful.
   *
   * \sa addWidget(WWidget *), removeItem(WLayoutItem *)
   */
  bool removeWidget(WWidget *widget);

  /*! \brief Returns the number of items in this layout.
   *
   * This may be a theoretical number, which is greater than the
   * actual number of items. It can be used to iterate over the items
   * in the layout, in conjunction with itemAt().
   */
  virtual int count() const = 0;

  /*! \brief Returns the layout item at a specific <i>index</i>.
   *
   * If there is no item at the \p index, \c 0 is returned.
   *
   * \sa indexOf(WLayoutItem *) const, count()
   */
  virtual WLayoutItem *itemAt(int index) const = 0;

  /*! \brief Returns the index of a given <i>item</i>.
   *
   * The default implementation loops over all items, and returns the
   * index for which itemAt(index) equals \p item.
   *
   * \sa itemAt(int) const
   */
  virtual int indexOf(WLayoutItem *item) const;

  /*! \brief Finds the widget item associated with the given <i>widget</i>.
   */
  virtual WWidgetItem *findWidgetItem(WWidget *widget);

  /*! \brief Provides a hint to the layout implementation.
   *
   * In some cases, a layout implementation may require some hints for
   * rendering its contents. Possible hints are indicated in the
   * reference documentation for each layout manager.
   */
  void setLayoutHint(const std::string& name, const std::string& value);

  virtual WWidget *widget() { return 0; }
  virtual WLayout *layout() { return this; }
  virtual WLayout *parentLayout() const;

  WLayoutItemImpl *impl() const { return impl_; }

  /*! \brief Set contents margins (in pixels).
   *
   * The default contents margins are 9 pixels in all directions.
   *
   * \note Only used when the layout manager is applied to a WContainerWidget.
   *
   * \sa setContentsMargins()
   */
  void setContentsMargins(int left, int top, int right, int bottom);

#ifndef WT_TARGET_JAVA
  /*! \brief Returns the contents margins.
   *
   * \sa setContentsMargins()
   */
  void getContentsMargins(int *left, int *top, int *right, int *bottom) const;
#else // WT_TARGET_JAVA
  /*! \brief Returns a contents margin.
   *
   * \sa setContentsMargins()
   */
  int getContentsMargin(Side side) const;
#endif // WT_TARGET_JAVA

  /*! \brief Removes and deletes all child widgets and nested layouts.
   *
   * This is similar to WContainerWidget::clear(), with the exception that
   * the layout itself is not deleted.
   */
  virtual void clear() = 0;

protected:
  /*! \brief Create a layout.
   */
  WLayout();

  /*! \brief Update the layout.
   *
   * Must be called whenever some properties of the layout have changed.
   */
  void update(WLayoutItem *item = 0);

  /*! \brief Update the layout, adding the given layout <i>item</i>.
   *
   * Must be called from the implementation of addItem(WLayoutItem *)
   */
  void updateAddItem(WLayoutItem *item);

  /*! \brief Update the layout, remove the given layout <i>item</i>.
   *
   * Must be called from the implementation of removeItem(WLayoutItem *)
   */
  void updateRemoveItem(WLayoutItem *item);

  /*! \brief Set the layout in the <i>parent</i>.
   *
   * Must be called from the constructor after the layout has been fully
   * created (since it will call virtual methods count() and itemAt()).
   */
  void setLayoutInParent(WWidget *parent);

  /*! \brief Clears and deletes an item.
   *
   * This also deletes nested widgets and layouts.
   *
   * \sa clear()
   */
  void clearLayoutItem(WLayoutItem *item);

private:
  struct Hint {
    Hint(const std::string& aName, const std::string& aValue)
      : name(aName), value(aValue) { }
    std::string name;
    std::string value;
  };

  typedef std::vector<Hint> HintsList;

  int    *WT_ARRAY margins_;
  WLayoutItemImpl *impl_;
  HintsList       *hints_;

  virtual void setParentWidget(WWidget *parent);
  virtual void setParentLayout(WLayout *parentLayout);

  friend class WWidget;
};

}

#endif // WLAYOUT_H_
