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

#include <boost/function.hpp>

#include <Wt/WInteractWidget>
#include <Wt/WString>

namespace Wt {

/*! \class WTemplate Wt/WTemplate Wt/WTemplate
 *  \brief A widget that renders an XHTML template.
 *
 * The XHTML template may contain references to variables which
 * replaced by strings are widgets.
 *
 * Since the template text may be supplied by a WString, you can
 * conveniently store the string in a message resource bundle, and
 * make it localized by using WString::tr().
 *
 * Placeholders (for variables and functions) are delimited by:
 * <tt>${...}</tt>. To use a literal <tt>"${"</tt>, use
 * <tt>"$${"</tt>.
 *
 * Usage example:
 * \if cpp
 * \code
 * WString userName = ...;
 *
 * WTemplate *t = new WTemplate();
 * t->setTemplateText("<div> How old are you, ${friend} ? ${age-input} </div>");
 *
 * t->bindString("friend", userName, PlainText);
 * t->bindWidget("age-input", ageEdit_ = new WLineEdit());
 * \endcode
 * \elseif java
 * \code
 * WString userName = ...;
 *
 * WTemplate t = new WTemplate();
 * t.setTemplateText("<div> How old are you, ${friend} ? ${age-input} </div>");
 *
 * t.bindString("friend", userName, PlainText);
 * t.bindWidget("age-input", ageEdit_ = new WLineEdit());
 * \endcode
 * \endif
 *
 * There are currently three syntactic constructs defined: variable
 * place holders, functions and conditional blocks.
 *
 * <h3>A. Variable placeholders</h3>
 *
 * <tt>${var}</tt> defines a placeholder for the variable "var", and
 * gets replaced with whatever is bound to that variable:
 * - a widget, using bindWidget()
 * - a string value, using bindString() or bindInt()
 * - or in general, the result of resolveString() and resolveWidget()
 *   methods.
 *
 * Optionally, additional arguments can be specified using the following
 * syntax:
 *
 * <tt>${var arg1="A value" arg2='A second value'}</tt>
 *
 * The arguments can thus be simple simple strings or quoted strings
 * (single or double quoted). These arguments are applied to a
 * resolved widget in applyArguments() and currently supports only
 * style classes.
 *
 * You can bind widgets and values to variables using bindWidget(),
 * bindString() or bindInt() or by reimplementing the resolveString()
 * and resolveWidget() methods.
 *
 * \note The use of XML comments (<tt>&lt;!-- ... --&gt;</tt>)
 *       around variables that are bound to widgets will result in bad
 *       behaviour since the template parser is ignorant about these
 *       comments and the corresponding widgets will believe that they
 *       are rendered but aren't actually.
 *
 * <h3>B. %Functions</h3>
 *
 * <tt>${fun:arg}</tt> defines a placeholder for applying a function
 * "fun" to an argument "arg".
 *
 * Optionally, additional arguments can be specified as with a
 * variable placeholder.
 *
 * Functions are resolved by resolveFunction(), and the default implementation
 * considers functions bound with addFunction(). 
 * There are currently three functions that are generally useful:
 * - \link Functions::tr\endlink : resolves a localized strings, this is 
 *   convenient to create a language neutral template, which contains 
 *   translated strings
 * - \link Functions::id\endlink : resolves the id of a bound widget, this 
 *   is convenient to bind &lt;label&gt; elements to a form widget using its 
 *   for attribute.
 * - \link Functions::block\endlink : recursively renders another string as
 *   macro block optional arguments substituted before processing template
 *   substitution.
 * \endif
 *
 * For example, the following template uses the "tr" function to translate
 * the age-label using the "age-label" internationalized key.
 *
 * \if cpp
 * \code
 * WTemplate *t = new WTemplate();
 * t->addFunction("tr", &WTemplate::Functions::tr);
 * t->setTemplateText("<div> ${tr:age-label} ${age-input} </div>");
 * t->bindWidget("age-input", ageEdit_ = new WLineEdit());
 * \endcode
 * \elseif java
 * \code
 * WTemplate t = new WTemplate();
 * t.setTemplateText("<div> ${tr:age-label} ${age-input} </div>");
 * t.addFunction("tr", WTemplate.Functions.tr);
 * t.bindWidget("age-input", ageEdit = new WLineEdit());
 * \endcode
 * \endif
 *
 * <h3>C. Conditional blocks</h3>
 *
 * <tt>${&lt;cond&gt;}</tt> starts a conditional block with a condition name
 * "cond", and must be closed by a balanced <tt>${&lt;/cond&gt;}</tt>.
 *
 * For example:
 * \if cpp
 * \code
 * WTemplate *t = new WTemplate();
 * t->setTemplateText("<div> ${<if-register>} Register ... ${</if-register>}</div>");
 * t->setCondition("if-register", true);
 * \endcode
 * \elseif java
 * \code
 * WTemplate t = new WTemplate();
 * t.setTemplateText("<div> ${<if-register>} Register ... ${</if-register>}</div>");
 * t.setCondition("if-register", true);
 * \endcode
 * \endif
 *
 * Conditions are set using setCondition().
 *
 * \if cpp
 * The template can return a bound widget using resolve(), which already
 * tries to cast the widget to the proper type.
 * \endif
 *
 * <h3>CSS</h3>
 *
 * This widget does not provide styling, 
 * and can be styled using inline or external CSS as appropriate.
 */
class WT_API WTemplate : public WInteractWidget
{
private:
  bool _tr(const std::vector<WString>& args, 
	   std::ostream& result);
  bool _block(const std::vector<WString>& args,
              std::ostream& result);
  bool _id(const std::vector<WString>& args, 
	   std::ostream& result);

public:
#ifndef WT_TARGET_JAVA
  /*! \brief A function type
   *
   * \sa addFunction()
   * \sa Functions::tr, Functions::id, Functions::block
   */
  typedef boost::function<bool(WTemplate *t, const std::vector<WString>& args,
			       std::ostream& result)> Function;

#else
  /*! \brief A function interface type
   *
   * \sa addFunction()
   * \sa Functions::tr, Functions::id, Functions::block
   */
  class Function {
  public:
    virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
			  std::ostream& result) const = 0;

  };

private:
  class TrFunction : public Function {
  public:
    virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
			  std::ostream& result) const;
  };

  class BlockFunction : public Function {
  public:
    virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
                          std::ostream& result) const;
  };

  class IdFunction : public Function {
  public:
    virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
			  std::ostream& result) const;
  };
public:
#endif
  /*! \brief A collection of predefined functions
   *
   * \sa addFunction()
   */
  struct WT_API Functions
  {
    /*! \brief A function that resolves to a localized string.
     *
     * For example, when bound to the function <tt>"tr"</tt>, template
     * that contains the placeholder
     * \code
     *   ... ${tr:name} ...
     * \endcode
     * will be resolved to the value of:
     * \code
     *   WString::tr("name")
     * \endcode
     *
     * \sa addFunction()
     */
#ifndef WT_TARGET_JAVA
    static bool tr(WTemplate *t, const std::vector<WString>& args,
		   std::ostream& result);
#else
    static Function& tr = TrFunction();
#endif

    /*! \brief A function that renders a macro block.
     *
     * The function will consider the first argument as the key
     * for a localized string that is a macro block, and additional arguments
     * as positional parameters in that block.
     *
     * For example, a template that contains:
     * \code
     * ...
     * ${block:form-field category}
     * ...
     * \endcode
     *
     * would look-up the following message:
     *
     * \code
     * <message id="form-field">
     *    <div class="control-group">
     *       ${{1}-info}
     *    </div>
     * </message>
     * \endcode
     *
     * and render as:
     *
     * \code
     * ...
     * <div class="control-group">
     *   ${category-info}
     * </div>
     * ...
     * \endcode
     */
#ifndef WT_TARGET_JAVA
    static bool block(WTemplate *t, const std::vector<WString>& args,
		      std::ostream& result);
#else
    static Function& block = BlockFunction();
#endif

    /*! \brief A function that resolves the id of a bound widget
     *
     * For example, when bound to the function <tt>"id"</tt>, template text
     * that contains a place-holder
     * \code
     *   ... ${id:name} ...
     * \endcode
     *
     * will be resolved to the value of:
     * \if cpp
     * \code
     *   t->resolveWidget("name")->id()
     * \endcode
     * \elseif java
     * \code
     *   t.resolveWidget("name").id()
     * \endcode
     * \endif
     *
     * This is useful for binding labels to input elements.
     *
     * \sa addFunction()
     */
#ifndef WT_TARGET_JAVA
    static bool id(WTemplate *t, const std::vector<WString>& args,
		   std::ostream& result);
#else
    static Function& id = IdFunction();
#endif // WT_TARGET_JAVA
  };

  /*! \brief Creates a template widget.
   */
  WTemplate(WContainerWidget *parent = 0);

  /*! \brief Creates a template widget with given template.
   *
   * The \p templateText must be proper XHTML, and this is checked
   * unless the XHTML is resolved from a message resource bundle. This
   * behavior is similar to a WText when configured with the
   * Wt::XHTMLText textformat.
   */
  WTemplate(const WString& text, WContainerWidget *parent = 0);

  /*! \brief Returns the template.
   *
   * \sa setTemplateText()
   */
  const WString& templateText() const { return text_; }

  /*! \brief Sets the template text.
   *
   * The \p text must be proper XHTML, and this is checked unless the
   * XHTML is resolved from a message resource bundle or TextFormat is
   * Wt::XHTMLUnsafeText. This behavior is similar to a WText when
   * configured with the Wt::XHTMLText textformat.
   *
   * Changing the template text does not clear() bound widgets or
   * values.
   *
   * \sa clear()
   */
  void setTemplateText(const WString& text, TextFormat textFormat = XHTMLText);

  /*! \brief Binds a string value to a variable.
   *
   * Each occurrence of the variable within the template will be
   * substituted by its value.
   *
   * Depending on the \p textFormat, the \p value is validated according
   * as for a WText.
   *
   * \sa bindWidget(), bindInt()
   * \sa resolveString()
   */
  virtual void bindString(const std::string& varName, const WString& value,
			  TextFormat textFormat = XHTMLText);

  /*! \brief Binds an integer value to a variable.
   *
   * \sa bindString()
   */
  void bindInt(const std::string& varName, int value);

  /*! \brief Binds a widget to a variable.
   *
   * The corresponding variable reference within the template will be
   * replaced with the widget (rendered as XHTML). Since a single
   * widget may be instantiated only once in a template, the variable
   * \p varName may occur at most once in the template, and the
   * \p widget must not yet be bound to another variable.
   *
   * If a widget was already bound to the variable, it is deleted
   * first. If previously a string or other value was bound to the
   * variable, it is removed.
   *
   * You may also pass a \c 0 \p widget, which will resolve to an empty
   * string.
   *
   * \sa bindString()
   * \sa resolveWidget()
   */
  virtual void bindWidget(const std::string& varName, WWidget *widget);

  /*! \brief Unbinds a widget.
   *
   * This removes a previously bound widget and unbinds the
   * corresponding variable, effectively undoing the effect of
   * bindWidget().
   *
   * \if cpp
   * The widget is not deleted, but returned instead.
   * \endif cpp
   */
  WWidget *takeWidget(const std::string& varName);

  /*! \brief Binds an empty string to a variable.
   *
   * If a widget was bound to the variable, it is deleted first.
   *
   * \sa bindString()
   */
  void bindEmpty(const std::string& varName);

  /*! \brief Binds a function.
   *
   * Functions are useful to automatically resolve placeholders.
   *
   * The syntax for a function 'fun' applied to a single argument
   * 'bla' is:
   *
   * <tt>${fun:bla}</tt>
   *
   * There are three predefined functions, which can be bound using:
   * \if cpp
   * \code
   * WTemplate *t = ...;
   * t->addFunction("id", &WTemplate::Functions::id);
   * t->addFunction("tr", &WTemplate::Functions::tr);
   * t->addFunction("block", &WTemplate::Functions::block);
   * \endcode
   * \else
   * \code
   * WTemplate t = ...;
   * t.addFunction("id", WTemplate.Functions.id);
   * t.addFunction("tr", WTemplate.Functions.tr);
   * t.addFunction("block", WTemplate.Functions.block);
   * \endcode
   * \endif
   */
#ifndef WT_TARGET_JAVA
  void addFunction(const std::string& name, const Function& function);
#else
  void addFunction(const std::string& name, const Function *function);
#endif

  /*! \brief Sets a condition.
   *
   * This enables or disables the inclusion of a conditional block.
   *
   * The default value of all conditions is \c false.
   */
  void setCondition(const std::string& name, bool value);

  /*! \brief Returns a condition value.
   *
   * \sa setCondition()
   */
  bool conditionValue(const std::string& name) const;

  /*! \brief Resolves the string value for a variable name.
   *
   * This is the main method used to resolve variables in the template
   * text, during rendering.
   *
   * The default implementation considers first whether a string was
   * bound using bindString(). If so, that string is returned. If
   * not, it will attempt to resolve a widget with that variable name
   * using resolveWidget(), and render it as XHTML. If that fails too,
   * handleUnresolvedVariable() is called, passing the initial arguments.
   *
   * You may want to reimplement this method to provide on-demand
   * loading of strings for your template.
   *
   * The result stream expects a UTF-8 encoded string value.
   *
   * \warning When specializing this class, you need to make sure that
   * you append proper XHTML to the \p result, without unsafe active
   * contents. The format() methods may be used for this purpose.
   *
   * \sa renderTemplate()
   */
  virtual void resolveString(const std::string& varName,
			     const std::vector<WString>& args,
			     std::ostream& result);

  /*! \brief Handles a variable that could not be resolved.
   *
   * This method is called from resolveString() for variables that could
   * not be resolved.
   *
   * The default implementation implementation writes 
   * "??" + varName + "??"  to the result stream.
   *
   * The result stream expects a UTF-8 encoded string value.
   *
   * \warning When specializing this class, you need to make sure that
   * you append proper XHTML to the \p result, without unsafe active
   * contents. The format() methods may be used for this purpose.
   *
   * \sa resolveString()
   */
   virtual void handleUnresolvedVariable(const std::string& varName,
                                         const std::vector<WString>& args,
                                         std::ostream& result);

  /*! \brief Resolves a widget for a variable name.
   *
   * The default implementation returns a widget that was bound using
   * bindWidget().
   *
   * You may want to reimplement this method to create widgets
   * on-demand. All widgets that are returned by this method are
   * reparented to the WTemplate, so they will be deleted when the
   * template is destroyed, but they are not deleted by clear() (unless
   * bind was called on them as in the example below).
   *
   * This method is typically used for delayed binding of widgets.
   * Usage example:
   * \if cpp
   * \code
   * if (Wt::Widget *known = WTemplate::resolveWidget(varName)) {
   *   return known;
   * } else {
   *   if (varName == "age-input") {
   *     Wt::WWidget *w = new Wt::WLineEdit(); // widget only created when used
   *     bind(varName, w);
   *     return w;
   *   }
   * }
   * \endcode
   * \elseif java
   * \code
   * if (Widget known = super.resolveWidget(varName)) {
   *   return known;
   * } else {
   *   if (varName == "age-input") {
   *     WWidget *w = new WLineEdit(); // widget only created when used
   *     bind(varName, w);
   *     return w;
   *   }
   * }
   * \endcode
   * \endif
   */
  virtual WWidget *resolveWidget(const std::string& varName);

  /*! \brief Resolves a function call.
   *
   * This resolves a function with name \p name, and one or more arguments
   * \p args, and writes the result into the stream \p result. The method
   * returns whether a function was matched and applied.
   *
   * The default implementation considers functions that were bound
   * using addFunction().
   *
   * \sa addFunction()
   */
  virtual bool resolveFunction(const std::string& name,
			       const std::vector<WString>& args,
			       std::ostream& result);

  /*! \brief Returns a widget for a variable name.
   *
   * This is a convience method, which calls resolveWidget() and casts
   * the result to type \p T. You may use this method to fetch widgets
   * that have previously been bound using bindWidget().
   */
  template <typename T> T resolve(const std::string& varName);

  /*! \brief Erases all variable bindings.
   *
   * Removes all strings and deletes all widgets that were previously
   * bound using bindString() and bindWidget().
   *
   * This also resets all conditions set using setCondition(), but
   * does not remove functions added with addFunction()
   */
  virtual void clear();

  /*! \brief Enables internal path anchors in the XHTML template.
   *
   * Anchors to internal paths are represented differently depending
   * on the session implementation (plain HTML, Ajax or HTML5
   * history). By enabling this option, anchors which reference an
   * internal path (by referring a URL of the form
   * <tt>href="#/..."</tt>), are re-encoded to link to the internal
   * path.
   *
   * The default value is \c false.
   *
   * \sa WAnchor::setRefInternalPath()
   */
  void setInternalPathEncoding(bool enabled);

  /*! \brief Returns whether internal paths are enabled.
   *
   * \sa setInternalPathEncoding()
   */
  bool hasInternalPathEncoding() const { return encodeInternalPaths_; }

  virtual void refresh();

  /*! \brief Renders the template into the given result stream.
   *
   * The default implementation will call renderTemplateText() with the
   * templateText().
   */
  virtual void renderTemplate(std::ostream& result);

  /*! \brief Renders a template into the given result stream.
   *
   * The default implementation will parse the template, and resolve variables
   * by calling resolveString().
   *
   * You may want to reimplement this method to manage resources that are
   * needed to load content on-demand (e.g. database objects), or support
   * a custom template language.
   */
  void renderTemplateText(std::ostream& result, const WString& templateText);

protected:
  /*! \brief Applies arguments to a resolved widget.
   *
   * Currently only a <tt>class</tt> argument is handled, which adds
   * one or more style classes to the widget \p w, using
   * WWidget::addStyleClass().
   */
  virtual void applyArguments(WWidget *w, const std::vector<WString>& args);

  virtual void           updateDom(DomElement& element, bool all);
  virtual DomElementType domElementType() const;
  virtual void           propagateRenderOk(bool deep);

  /*! \brief Utility method to safely format an XHTML string.
   *
   * The string is formatted according to the indicated \p
   * textFormat. It is recommended to use this method when
   * specializing resolveString() to avoid security risks.
   */
  void format(std::ostream& result, const std::string& s,
	      TextFormat textFormat = PlainText);

  /*! \brief Utility method to safely format an XHTML string.
   *
   * The string is formatted according to the indicated \p
   * textFormat. It is recommended to use this method when
   * specializing resolveString() to avoid security risks.
   */
  void format(std::ostream& result, const WString& s,
	      TextFormat textFormat = PlainText);

  virtual void enableAjax();

private:
  typedef std::map<std::string, Function> FunctionMap;
  typedef std::map<std::string, std::string> StringMap;
  typedef std::map<std::string, WString> TemplateMap;
  typedef std::map<std::string, WWidget *> WidgetMap;
  typedef std::set<std::string> ConditionSet;

  std::set<WWidget *> *previouslyRendered_;
  std::vector<WWidget *> *newlyRendered_;

  FunctionMap functions_;
  StringMap strings_;
  TemplateMap nestedTemplates_;
  WidgetMap widgets_;
  ConditionSet conditions_;

  WString text_;

  bool encodeInternalPaths_, changed_;

  static std::size_t parseArgs(const std::string& text,
			       std::size_t pos,
			       std::vector<WString>& result);
};

template <typename T> T WTemplate::resolve(const std::string& varName)
{
  WWidget *w = resolveWidget(varName);
  return dynamic_cast<T>(w);
}


}

#endif // WTEMPLATE_H_
