// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2011 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WT_WTEMPLATE_FORM_VIEW_H_
#define WT_WTEMPLATE_FORM_VIEW_H_

#include <Wt/WTemplate>
#include <Wt/WFormModel>

namespace Wt {

/*! \class WTemplateFormView Wt/WTemplateFormView
 *  \brief A template-based View class form models.
 *
 * This implements a View to be used in conjunction with WFormModel
 * models to implement forms.
 *
 * For a model field, it uses a number of conventional variable names
 * to represent the label, editor, and validation messages in the
 * template:
 * - 'field': the form widget which contains the value
 * - 'field-label': the label
 * - 'field-info': a text that contains the validation message
 * - 'if:field': condition for the visibility of the field
 *
 * For a field with name 'field', a typical template uses blocks of
 * the following-format:
 *
 * \verbatim
 *   ${<if:field>}
 *     <label for="${id:field}">${field-label}</label>
 *     ${field} ${field-info}
 *   ${</if:field>}
 * \endverbatim
 *
 * The View may render fields of more than one model, and does not
 * necessarily need to render all information of each model: you can
 * call the updateViewField() and updateModelField() for individual
 * model fields.
 *
 * The updateView() method updates the view based on a model (e.g. to
 * propagate changed values or validation), while the updateModel() method
 * updates a model with values entered in the View.
 *
 * The view is passive: it will not perform any updates by itself of either
 * the View or Model. You will typically bind a method to the Ok button
 * and do:
 * \if cpp
 * \code
 * void MyView::okClicked()
 * {
 *   updateModel(model_);
 *   if (model_->validate()) {
 *     ...
 *   } else {
 *     updateView(model_);
 *   }
 * }
 * \endcode
 * \elseif java
 * \code
 * void okClicked()
 * {
 *   updateModel(this.model);
 *   if (this.model.validate()) {
 *     ...
 *   } else {
 *     updateView(this.model);
 *   }
 * }
 * \endcode
 * \endif
 */
class WT_API WTemplateFormView : public WTemplate
{
public:
  /*! \brief Constructor.
   */
  WTemplateFormView(WContainerWidget *parent = 0);

  /*! \brief Constructor.
   */
  WTemplateFormView(const WString& text, WContainerWidget *parent = 0);

  /*! \brief Sets the form widget for a given field.
   */
  void setFormWidget(WFormModel::Field field, WFormWidget *formWidget);

#ifndef WT_TARGET_JAVA
  /*! \brief Sets the form widget for a given field.
   *
   * This also defines the functions to update the view respectively the
   * model
   */
  void setFormWidget(WFormModel::Field field, WFormWidget *formWidget,
		     const boost::function<void ()>& updateViewValue,
		     const boost::function<void ()>& updateModelValue);
#else
#ifdef WT_BUILDING
  template<typename F1, typename F2>
  void setFormWidget(WFormModel::Field field, WFormWidget *formWidget,
		     F1 updateViewValue, F2 updateModelValue);
#endif
  /*! \brief Interface for custom update methods for field data.
   */
  class FieldView
  {
  public:
    /*! \brief Update the widget's value based on the model's data.
     */
    void updateViewValue() = 0;

    /*! \brief Update the model's data based on the widget's value.
     */
    void updateModelValue() = 0;
  };

  /*! \brief Sets the form widget for a given field.
   *
   * This also defines the functions to update the view respectively the
   * model
   */
  void setFormWidget(WFormModel::Field field, WFormWidget *formWidget,
		     FieldView *fieldView);
#endif

  /*! \brief Creates or updates a field in the View.
   *
   * This will update or create and bind widgets in the template to represent
   * the field. To create the form widget that implements the editing, it
   * calls createFormWidget().
   *
   * \note It's usually more convenient to reimplement updateViewValue()
   *       to support a non-textual value in the model.
   */
  virtual void updateViewField(WFormModel *model, WFormModel::Field field);

  /*! \brief Updates a field in the Model (<b>Deprecated</b>)
   *
   * Calls updateModelValue()
   *
   * \deprecated Reimplement updateModelValue() instead.
   */
  virtual void updateModelField(WFormModel *model, WFormModel::Field field);

  /*! \brief Updates the value in the View.
   *
   * The default implementation sets WFormModel::valueText() into
   * WFormWidget::setValueText()
   */
  virtual void updateViewValue(WFormModel *model, WFormModel::Field field,
			       WFormWidget *edit);

  /*! \brief Updates a value in the Model.
   *
   * The default implementation sets WFormModel::setValue() with
   * WFormWidget::valueText().
   */
  virtual void updateModelValue(WFormModel *model, WFormModel::Field field,
				WFormWidget *edit);

  /*! \brief Updates the View.
   *
   * This creates or updates all fields in the view.
   *
   * \sa updateViewField(), WFormModel::fields()
   */
  virtual void updateView(WFormModel *model);

  /*! \brief Updates the Model.
   *
   * This creates or updates all field values in the model.
   *
   * \sa updateModelField(), WFormModel::fields()
   */
  virtual void updateModel(WFormModel *model);

protected:
  /*! \brief Creates a form widget.
   *
   * This method is called by updateViewField() when it needs to
   * create a form widget for a field, and none was specified using
   * setFormWidget().
   */
  virtual WFormWidget *createFormWidget(WFormModel::Field field);

  /*! \brief Indicates the validation result.
   *
   * The default implementation will set "Wt-valid" or "Wt-invalid" on the
   * form widget, and "Wt-error" on the info text.
   */
  virtual void indicateValidation(WFormModel::Field field,
				  bool validated,
				  WText *info,
				  WFormWidget *edit,
				  const WValidator::Result& validation);
private:
  struct FieldData {
    FieldData();

    WFormWidget *formWidget;
#ifndef WT_TARGET_JAVA
    boost::function<void ()> updateView, updateModel;
#else
    FieldView *updateFunctions;
#endif
  };

  typedef std::map<std::string, FieldData> FieldMap;
  FieldMap fields_;

  void init();
};

}

#endif // WT_TEMPLATE_FORM_VIEW_H_
