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

#include <string>
#include <vector>
#include <iosfwd>
#include "WDllDefs.h"

#include <WStringUtil>

/*! \file WString */

namespace Wt {

/*! \class WString WString WString
 *  \brief %Wt unicode String class, with support for localization.
 *
 * %Wt offers this string to facilitate handling of unicode text through
 * the user interface, as well as to offer support for localized text
 * using message resource bundles.
 *
 * A %WString may be constructed from a std::string, std::wstring or
 * c-style strings (const char * and const wchar_t *), and converted
 * to each of these strings. In addition, it supports conversion from and
 * to UTF8 unicode encoded strings.
 *
 * By using the static functions WString::tr() (or WWidget::tr()), one
 * may construct a localized string. The key is used to retrieve its
 * current value from the application's message-resource
 * bundles. Arguments in the message, denoted using {<i>n</i>} for the
 * <i>n</i>'th argument, may be substituted by arguments set using
 * arg(int) and arg(std::string).
 *
 * By calling WApplication::refresh(), the contents of every %WString
 * may be refreshed by the owner (and this is done so for all %Wt
 * widgets that own a %WString), by calling refresh(). In this way, the
 * contents is adapted to a possibly changed locale.
 *
 * This string class does not provide anything more than basic
 * manipulations. Instead, you should convert to a standard library
 * string class to manipulate the string contents.
 *
 * \sa WApplication::messageResourceBundle()
 * \sa WApplication::locale()
 */
class WT_API WString
{
public:
  /*! \brief Construct a %WString from a wide C string
   */
  WString(const wchar_t *value = 0);

  /*! \brief Copy constructor
   */
  WString(const WString& other);

  /*! \brief Construct a %WString from a wide C++ string
   */
  WString(const std::wstring value);

  /*! \brief Construct a %WString from a C string.
   */
  WString(const char *value);

  /*! \brief Construct a %WString from a C++ string.
   */
  WString(const std::string value);

  /*! \brief Delete a %WString
   */
  ~WString();

  /*! \brief Assignment operator
   */
  WString& operator= (const WString& rhs);

  /*! \brief Comparison operator
   */
  bool operator== (const WString& rhs) const;

  /*! \brief Self-concatenation operator
   */
  WString& operator+= (const WString& rhs);

  /*! \brief Self-concatenation operator
   */
  WString& operator+= (const std::wstring rhs);

  /*! \brief Self-concatenation operator
   */
  WString& operator+= (const wchar_t *rhs);

  /*! \brief Self-concatenation operator
   */
  WString& operator+= (const std::string rhs);

  /*! \brief Self-concatenation operator
   */
  WString& operator+= (const char *rhs);

  /*! \brief Is the string empty ?
   */
  bool empty() const;

  /*! \brief Construct a %WString from a UTF8 unicode encoded string.
   */
  static WString fromUTF8(const std::string value);

  /*! \brief Get the value as a UTF8 unicode encoded string.
   *
   * For a localized string, returns the current localized value.
   *
   * \sa fromUTF8()
   */
  std::string toUTF8() const;

  /*! \brief Construct a localized string with the specified key.
   *
   * The key is looked up in the application message resource bundles. If
   * the key cannot be resolved, the value is set to ??key??.
   *
   * \sa WApplication::messageResourceBundle()
   */
  static WString tr(const char *key);

  /*! \brief Get the value as a wide C++ string.
   *
   * For a localized string, returns the current localized value.
   */
  std::wstring value() const;

  /*! \brief Get the value as a narrow C++ string.
   *
   * For a localized string, returns the current localized value.
   *
   * Any wide character is narrowed, possibly losing information. If
   * you wish to keep all information, use toUTF8() instead, which
   * encodes wide characters in the string.
   *
   * \sa toUTF8()
   */
  std::string narrow() const;

  /*! \brief Get the value as a wide C++ string.
   *
   * For a localized string, returns the current localized value.
   */
  operator std::wstring() const;

  /*! \brief Is this string literal or localized ?
   *
   * \sa tr()
   */
  bool literal() const { return !key_; }

  /*! \brief Get the key for this localized string.
   *
   * When the string is literal, the result is undefined.
   */
  const std::string key() const;

  /*! \brief Add a value for the next positional string argument of this
   *         localized string.
   *
   * In the resource, the <i>n</i>-th argument is reffered to as using
   * '{<i>n</i>}'. For example: a resource message '{1} bought {2}
   * apples in the shop.'  with first argument value 'Bart' and second
   * argument value '5' becomes: 'Bart bought 5 apples in the shop.'.
   */
  WString& arg(const std::wstring value);

  /*! \brief Add a value for the next positional string argument of this
   *         localized string.
   *
   * In the resource, the <i>n</i>-th argument is reffered to as using
   * '{<i>n</i>}'. For example: a resource message '{1} bought {2}
   * apples in the shop.'  with first argument value 'Bart' and second
   * argument value '5' becomes: 'Bart bought 5 apples in the shop.'.
   */
  WString& arg(const std::string value);

  /*! \brief Add a value for the next positional integer argument of this
   *         localized string.
   *
   * In the resource, the <i>n</i>-th argument is reffered to as using
   * '{<i>n</i>}'. For example: a resource message '{1} bought {2}
   * apples in the shop.'  with first argument value 'Bart' and second
   * argument value '5' becomes: 'Bart bought 5 apples in the shop.'.
   */
  WString& arg(int value);

  /*! \brief The list of arguments
   */
  const std::vector<std::wstring>& args() const;

  /*! \brief Refresh the message.
   *
   * For a localized message, this rereads the value from the message
   * resource bundle.
   *
   * Returns whether the value has changed.
   */
  bool refresh();

private:
  WString(const char *key, bool);

  std::wstring value_;

  void makeLiteral();

  struct Key {
    std::string               key_;
    std::vector<std::wstring> arguments_;
  };

  static std::vector<std::wstring> stArguments_;

  Key *key_;
};

/*! \brief Concatenate two WStrings
 */
extern WT_API WString operator+ (const WString& lhs, const WString& rhs);

/*! \brief Conatenate a WString with a C++ wide string
 */
extern WT_API WString operator+ (const WString& lhs, const std::wstring rhs);

/*! \brief Conatenate a WString with a C wide string
 */
extern WT_API WString operator+ (const WString& lhs, const wchar_t *rhs);

/*! \brief Conatenate a WStrin with a C++ string
 */
extern WT_API WString operator+ (const WString& lhs, const std::string rhs);

/*! \brief Conatenate a WString with a C string
 */
extern WT_API WString operator+ (const WString& lhs, const char *rhs);

/*! \brief Conatenate a C++ wide string with a WString
 */
extern WT_API WString operator+ (const std::wstring lhs, const WString& rhs);

/*! \brief Conatenate a C wide string with a WString
 */
extern WT_API WString operator+ (const wchar_t *lhs, const WString& rhs);

/*! \brief Conatenate a C++ string with a WString
 */
extern WT_API WString operator+ (const std::string lhs, const WString& rhs);

/*! \brief Conatenate a C string with a WString
 */
extern WT_API WString operator+ (const char *lhs, const WString& rhs);


/*! \brief Compare a C string with a WString
 */
extern WT_API bool operator== (const char *lhs, const WString& rhs);

/*! \brief Compare a C wide string with a WString
 */
extern WT_API bool operator== (const wchar_t *lhs, const WString& rhs);

/*! \brief Compare a C++ string with a WString
 */
extern WT_API bool operator== (const std::string lhs, const WString& rhs);

/*! \brief Compare a C++ wide string with a WString
 */
extern WT_API bool operator== (const std::wstring lhs, const WString& rhs);


/*! \brief Compare a C string with a WString
 */
extern WT_API bool operator!= (const char *lhs, const WString& rhs);

/*! \brief Compare a C wide string with a WString
 */
extern WT_API bool operator!= (const wchar_t *lhs, const WString& rhs);

/*! \brief Compare a C++ string with a WString
 */
extern WT_API bool operator!= (const std::string lhs, const WString& rhs);

/*! \brief Compare a C++ wide string with a WString
 */
extern WT_API bool operator!= (const std::wstring lhs, const WString& rhs);


/*! \brief Output a WString to a C++ wide stream
 */
extern WT_API std::wostream& operator<< (std::wostream& lhs, const WString& rhs);

/*! \brief Output a WString to a C++ stream
 */
extern WT_API std::ostream& operator<< (std::ostream& lhs, const WString& rhs);

/*! \brief <i>Deprecated</i> Alias to WString for the depreacated WMessage
 *         classes.
 *
 * WString provides all the functionality of WMessage, but is used more
 * consistently through the interface everywhere wide character support
 * is needed, instead of previously std::wstring.
 */
typedef WString WMessage;

}

#endif // WSTRING_H_
