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

#include <iostream>

#include <Wt/WObject>
#include <Wt/WString>

namespace Wt {

class WFormWidget;

/*! \class WValidator Wt/WValidator Wt/WValidator
 *  \brief A validator is used to validate user input according to
 *         pre-defined rules.
 *
 * A validator may be associated with a form widget using
 * WFormWidget::setValidator().
 *
 * The validator validates the user input. A validator may have a
 * split implementation to provide both validation at the client-side
 * (which gives instant feed-back to the user while editing), and
 * server-side validation (to be sure that the client was not tampered
 * with). The feed-back given by (client-side and server-side)
 * validation is reflected in the style class of the form field: a
 * style class of <tt>Wt-invalid</tt> is set for a field that is
 * invalid.
 *
 * This %WValidator only checks that mandatory fields are not empty.
 * This class is reimplemented in WDateValidator, WIntValidator,
 * WDoubleValidator, WLengthValidator and WRegExpValidator. All these
 * validators provibe both client-side and server-side validation.
 *
 * If these validators are not suitable, you can inherit from this
 * class, and provide a suitable implementation to validate() which
 * does the server-side validation. If you want to provide client-side
 * validation for your own validator, you may also reimplement
 * javaScriptValidate().
 *
 * \sa WFormWidget
 */
class WT_API WValidator : public WObject
{
public:
  /*! \brief The state in which validated input can exist.
   */
  enum State { Invalid,	     //!< The input is invalid.
	       InvalidEmpty, //!< The input is invalid (emtpy and mandatory).
	       Valid	     //!< The input is valid.
  };

  /*! \brief Creates a new validator.
   */
  WValidator(WObject *parent = 0);

  /*! \brief Creates a new validator.
   *
   * Indicate whether input is mandatory.
   *
   * \sa setMandatory(bool)
   */
  WValidator(bool mandatory, WObject *parent = 0);

  /*! \brief Destructor.
   *
   * The validator automatically removes itself from all formfields to
   * which it was associated.
   */
  ~WValidator();

  /*! \brief Sets if input is mandatory
   *
   * When an input is not mandatory, then an empty field is always
   * valid.
   */
  void setMandatory(bool how);

  /*! \brief Returns if input is mandatory.
   */
  bool isMandatory() const { return mandatory_; }

  /*! \brief Sets the message to display when a mandatory field is left blank
   *
   * The default value is "This field cannot be empty".
   */
  void setInvalidBlankText(const WString& text);

  /*! \brief Returns the message displayed when a mandatory field is left blank
   *
   * \sa setInvalidBlankText(const WString&)
   */
  WString invalidBlankText() const;

  /*! \brief This function attempts to change input to be valid according to
   *         the validator's rules.
   *
   * In general the function needs not to change the input into a
   * valid input. The default implementation does nothing. But it may
   * help the user in getting its input right.
   */
  virtual void fixup(WString& input) const;

  /*! \brief Validates the given input.
   *
   * This function returns the current validation state of the
   * input. The default implementation only checks whether a mandatory
   * field is not left blank.
   */
  virtual State validate(WT_USTRING& input) const;

  /*! \brief Provides Ext-compatible config options for client-side validation.
   */
  virtual void createExtConfig(std::ostream& config) const;

protected:
  /*! \brief Creates a Javascript expression that validates the input.
   *
   * The JavaScript expression should evaluate to an object with two
   * fields: a boolean <i>valid</i>, and a \p message that
   * indicates the problem if not valid.
   *
   * Return an empty string if you are not provide the client-side
   * validation.
   *
   * \sa inputFilter()
   */
  virtual std::string javaScriptValidate(const std::string& jsRef) const;

  /*! \brief Returns a regular expression that filters input.
   *
   * The returned regular expression is used to filter keys
   * presses. The regular expression should accept valid single
   * characters.
   *
   * For details on valid regular expressions, see WRegExpValidator.
   * As an example, "[0-9]" would only accept numbers as valid input.
   *
   * The default implementation returns an empty string, which does not
   * filter any input.
   *
   * \sa javaScriptValidate()
   */
  virtual std::string inputFilter() const;

  void repaint();

private:
  bool         mandatory_;
  WString      mandatoryText_;

  std::vector<WFormWidget *> formWidgets_;

  void addFormWidget(WFormWidget *w);
  void removeFormWidget(WFormWidget *w);

  friend class WFormWidget;
};

}

#endif // WVALIDATOR_H_
