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

#include <vector>
#include <string>
#include <set>

#include <WObject>
#include <WCssStyleSheet>
#include <WEvent>
#include <WString>
#include <WMessageResourceBundle>
#include <WSignal>

/*! \file WApplication */

namespace Wt {

class WApplication;
class WContainerWidget;
class WEnvironment;
class WResource;
class WServerPushResource;
class WebSession;
class WText;
class Iframe;
class UpdateLockImpl;
class WEvent;

extern WT_API void RemoveExposedSignal(EventSignalBase *s);
extern WT_API void AddExposedSignal(EventSignalBase *s);

/*! \brief Typedef for a function that creates WApplication objects.
 *
 * \sa WRun()
 */
typedef WApplication* (*ApplicationCreator)(const WEnvironment& env);

/*! \class WApplication WApplication WApplication
 *  \brief A class that represents an instance of a %Wt Application,
 *         corresponding to a single session.
 *
 * For every new session, an instance of Wt::WApplication must be
 * created, before creating widgets. For this purpose, the user passes
 * a function that creates applications to Wt::WRun(). A general
 * structure for starting a %Wt Application could be:
 *
 * \code
 *   WApplication *createApplication(const WEnvironment WEnvironment& env) {
 *     //
 *     // Optionally, check the environment and redirect to an error page.
 *     //
 *     bool valid = ...;
 *    
 *     if (!valid) {
 *       WApplication *app = new WApplication(env);
 *       app->redirect("error.html");
 *       app->quit();
 *       return app;
 *     }
 *
 *     WApplication *app = new WApplication(env);
 *
 *     //
 *     // Add widgets to app->root() and return the application object.
 *     //
 *     return app;
 *   }
 * \endcode
 *
 * Throughout the application, the instance is available through
 * WApplication::instance() (or through #wApp). The application may be
 * quited either by calling quit(), or because of a timeout (when the
 * user has closed the window, or crashed its computer or was eaten by
 * a virus). In either case, the application object is deleted,
 * allowing for cleanup of the entire widget tree, and any other
 * resources.
 *
 * The %WApplication object provides access to:
 * <ul>
 *   <li>WEnvironment information through environment(), which gives
 *     details about the user and start-up
 *     arguments.</li>
 *   <li>inline and external style sheets using styleSheet() and
 *     useStyleSheet() respectively.</li>
 *   <li>the top-level widget, which is the root of the widget hierarchy,
 *     with root().</li>
 *   <li>localisation information and message resources bundles, with
 *     setLocale(), locale() and messageResourceBundle().
 *   <li>the maximum configured request size (maximumRequestSize()) and
 *     a signal WApplication::requestTooLarge to react to too large
 *     requests.</li>
 *   <li>defining cookies using setCookie(). These cookies may provide
 *     context across sessions, and may be inspected using
 *     WEnvironment::getCookie() in a future session.</li>
 *   <li>support for browser history (back and forward buttons), and
 *     bookmarks using the setState() and state() methods, and
 *     the WApplication::stateChanged signal.</li>
 *   <li>support for server-initiated updates with enableUpdates(),
 *     triggerUpdate() and getUpdateLock().</li>
 * </ul>
 *
 */
class WT_API WApplication : public WObject
{
public:
  /*! \brief Enumeration that indicates the Ajax communication method.
   *
   * \sa setAjaxMethod()
   */
  enum AjaxMethod {
    XMLHttpRequest,  //!< Use the XMLHttpRequest object (real AJAX)
    DynamicScriptTag //!< Use dynamic script tags (for cross-domain AJAX)
  };

  /*! \brief Typedef for a function that creates WApplication objects.
   *
   * \sa WRun()
   */
  typedef Wt::ApplicationCreator ApplicationCreator;

  /*! \brief Construct a WApplication
   */
  WApplication(const WEnvironment& environment);

  /*! \brief Destroys the WApplication.
   *
   * This automatically destroys root(), and as a consequence the entire
   * widget tree.
   */
  ~WApplication();

  /*! \brief The environment for this application session.
   *
   * This is the environment that was used when constructing the
   * application.
   */
  const WEnvironment& environment() const;

  /*! \brief Access the inline style sheet of this application.
   *
   *  WWidgets may allow configuration of their look and feel through style
   *  classes. These may be defined in this inline stylesheet. Currently,
   *  the stylesheet may only be defined before the application is started,
   *  subsequent changes will not be reflected in the application.
   *
   * \sa useStyleSheet()
   */
  WCssStyleSheet& styleSheet() { return styleSheet_; }

  /*! \brief Add an external style sheet.
   *
   * If not empty, dep is a string that is used to make the stylesheet
   * browser-dependent. This works only to differentiate between
   * specific versions of Microsoft Internet Explorer versions versus
   * other browsers.  Values for dep are for example "gte IE 5" or
   * "!IE 7".
   *
   * \sa styleSheet()
   */
  void useStyleSheet(const std::string& uri,
		     const std::string& dep = std::string());

  /*! \brief The root container of this application.
   *
   *  This is the top-level container for displaying widgets in the
   *  application.
   */
  WContainerWidget *root() const { return widgetRoot_; }

  void bindWidget(WWidget *widget, const std::string& divId);

  /*! \brief Get the application Url.
   *
   * Returns the (relative) URL for this application, including session ID
   * if needed (if using URL rewriting for session tracking).
   *
   * \sa redirect()
   */
  std::string url() const;

  /*! \brief Set the application title.
   *
   * Set the title that appears as the browser window title.
   */
  void setTitle(const WString& text);

  /*! \brief Get the application title.
   *
   * Returns the currently set application title.
   */
  const WString& title() const { return title_; }

  /*! \brief Get the application instance.
   *
   * This is the same as the global variable #wApp.
   */
  static WApplication *instance();

  /*! \brief Get the message resource bundle for this application.
   *
   * \sa WString::tr(const char *key)
   */
  WMessageResourceBundle& messageResourceBundle()
    { return messageResourceBundle_; }

  /*! \brief Set the current locale.
   *
   * Specifying an empty locale assumes the default locale.
   * A different value (such as e.g. "nl") will cause WString values to be
   * resolved in the respect message resource files.
   *
   * When the locale get changed, refresh() is called which will re-localize
   * messages.
   *
   * \sa WMessageResourceBundle::use(), WString::tr()
   */
  void setLocale(const std::string& locale);

  /*! \brief Get the currently used locale.
   *
   * The default locale is copied from the environment, but may be changed
   * using setLocale().
   *
   * \sa setLocale(const std::string&)
   * \sa WEnvironment::locale()
   */
  std::string locale() const { return locale_; }

  /*! \brief Refresh the application.
   *
   * This method is called in response to the user hitting the refresh
   * (or reload) button, and causes the application to refresh its data,
   * including messages from message-resource bundles.
   */
  virtual void refresh();

  /*! \brief Get the current maximum size of a request to the application.
   *
   * The maximum request size may be configured in the configuration file.
   */
  int maximumRequestSize() const;

  /*! \brief Redirect the application to another location.
   *
   * The client will be redirected to a new location. Use this in
   * conjunction with quit() if you want to the application to be
   * terminated as well. redirect() does not imply quit(), since it
   * may be useful to switch between a non-secure and secure (SSL)
   * transport connection
   */
  void redirect(const std::string& url);

  /*! \brief Change the threshold for two-phase rendering.
   *
   * This changes the threshold for the communication size (in bytes) to
   * render invisible changes in one go. If the bandwidth for
   * rendering the invisible changes exceed the threshold, they will
   * be fetched in a second communication, after the visible changes
   * have been rendered.
   *
   * The value is a trade-off: setting it smaller will always use two-phase
   * rendering, increasing the total render time. Setting it too large will
   * increase the latency to render the visible changes, which will only
   * be rendered after all changes have been communicated.
   *
   * The initial value is read from the configuration file.
   */
  void setTwoPhaseRenderingThreshold(int size);

  /*! \brief Set a new cookie.
   *
   * The name must be a valid cookie name (of type 'token': no special
   * characters or separators, see RFC2616 page 16). The value may be
   * anything. Specify the maximum age (in seconds) after which the
   * client must discard the cookie. To delete a cookie, use a value of '0'.
   *
   * By default the cookie only applies to the current path on the
   * current domain. To set a proper value for domain, see also RFC2109.
   */
  void setCookie(const std::string& name, const std::string& value,
		 int maxAge, const std::string& domain = "",
		 const std::string& path = "");

  /*! \brief Checkpoint the current application state with a key/value pair.
   *
   * The user may browse through application states using the browser back
   * and forward buttons, or bookmark a particular state of your application.
   *
   * An application object (such as a widget) that wishes to generate history
   * events, and respond to state changes, should:
   * <ul>
   *   <li>reserve a unique key for itself;</li>
   *   <li>use calls to setState() to indicate a new state;</li>
   *   <li>examine an initial state using state() when the object is created,
   *     which may reflect a bookmarked state;</li>
   *   <li>respond to state changes by listening to the
   *     WApplication::stateChanged signal for state related to its key.</li>
   * </ul>
   *
   * For an example, see the WMenu implementation.
   *
   * This feature currently only works when Ajax and JavaScript are
   * enabled, and only for Firefox and Internet Explorer, and requires
   * the following resource:
   *
   * <ul>
   * <li><i>resourcesURL</i>/dhtml_dhtmlHistory.js</li>
   * </ul>
   *
   * This file may be found in the resources/ folder of the %Wt distribution. 
   *
   * The default value for <i>resourcesURL</i> is "resources/". This
   * value may be overridden with any valid URL which points to the
   * location where this file may be found, by configuring the
   * <i>resourcesURL</i> property in your %Wt configuration file.
   *
   * \sa state(), stateChanged
   */
  void setState(const std::string& key, const std::string& value);

  /*! \brief Get the current application state value associated with a
   *         specific key.
   *
   * \sa setState()
   */
  std::string state(const std::string& key) const;

  /*! \brief Signal which is emitted when the application state changes
   *         because the user navigates through the browser history.
   *
   * An application object that wishes to react to state changes should
   * listen to this signal. 
   *
   * \sa setState()
   */
  Signal<std::string, std::string> stateChanged;

  /*! \brief Unique identifier for the current session
   *
   * The session id is a string that uniquely identifies the current session.
   * Note that the actual contents has no particular meaning and client
   * applications should in no way try to interpret its value.
   */
  std::string sessionId() const;

  WebSession *session() { return session_; }

  /*! \brief Enable server-initiated updates.
   *
   * By default, updates to the user interface are possible only at
   * startup, during any event (in a slot), or at regular time points
   * using WTimer. This is the normal %Wt event loop.
   *
   * In some cases, one may want to modify the user interface from a
   * second thread, outside the event loop, or from socket events
   * (using the WSocketNotifier). While this may be worked around by
   * the WTimer, in some cases, there are bandwidth and processing
   * overheads associated which may be unnecessary, and which create a
   * trade-off with time resolution of the updates.
   *
   * A call to this method starts a so-called "server push". Widgets
   * may then be modified, created or deleted outside of the event
   * loop (from another thread), and are subsequently propagated by
   * calling triggerUpdate().
   *
   * <i>This works only if JavaScript is available on the client, and
   * is not considered a production quality feature (there are some
   * unwanted side effects that have to do with typical browser
   * limitations, such as the maximum number of simultaneous open
   * connections to a single web server).</i>.
   *
   * \sa triggerUpdate()
   */
  void enableUpdates();

  /*! \brief Are server-initiated updates enabled ?
   *
   * True if server-initiated updates were enabled by a previous call to
   * enableUpdates().
   */
  bool updatesEnabled() const;

  /*! \brief Propagate server-initiated updates.
   *
   * Propagate changes made to the user interface outside of the main
   * event loop. This is only possible after a call to
   * enableUpdates(), and must be done while holding the UpdateLock
   * (or from within a socket event, see WSocketNotifier).
   *
   * \sa enableUpdates(), getUpdateLock()
   */
  void triggerUpdate();

  /*! \brief A synchronisation lock for manipulating and updating the
   *         application and its widgets outside of the event loop.
   *
   * You need to get this lock only when you want to manipulate
   * widgets outside of the event loop. Inside the event loop, this
   * lock is already held by the library itself.
   *
   * \sa getUpdateLock();
   */
  class WT_API UpdateLock {
  public:
    /*! \brief Copy the lock.
     *
     * By copying the lock, the lock is transferred. The original object
     * becomes empty, and its destructor has no effect of releasing the lock.
     */
    UpdateLock(const UpdateLock&);

    /*! \brief Releases and destroys the scope dependent lock
     */
    ~UpdateLock();

  private:
    UpdateLock(WApplication& app);

    mutable UpdateLockImpl *impl_;

    friend class WApplication;
  };

  /*! \brief Get the lock for manipulating widgets outside the event loop.
   *
   * You need to keep this lock in scope while manipulating widgets
   * outside of the event loop. In normal cases, inside the %Wt event loop,
   * you do not need to care about it.
   *
   * \sa enableUpdates(), triggerUpdate()
   */
  UpdateLock getUpdateLock();

  /*! \brief Execute some JavaScript code.
   *
   * This method may be used to call some custom JavaScript code as
   * part of an event response.
   *
   * This function does not wait until the JavaScript is run, but returns
   * immediately. The JavaScript will be run when the event handling
   * is done.
   */
  void doJavaScript(const std::string& javascript, bool afterLoaded = true);

  /*! \brief Load a JavaScript library.
   *
   * Attempt to load a JavaScript library. The <i>symbol</i> is not
   * empty, the library is only inserted in the page if the given
   * symbol is not yet defined.
   *
   * Returns true when the library was not yet loaded for this
   * application.
   */
  bool require(const std::string& uri,
	       const std::string& symbol = std::string());

  /*! \brief Process UI events.
   *
   * You may call this method during a long operation to:
   * <ul>
   *   <li>Propagate widget changes to the client.</li>
   *   <li>Process UI events.</li>
   * </ul>
   *
   * This method starts a recursive event loop, blocking the current
   * thread, and resumes when all events have been processed.
   */
  void processEvents();

  /*! \brief Read a configuration property.
   *
   * Tries to read a configured value for the property
   * <i>name</i>. The method returns whether a value is defined for
   * the property, and sets it to <i>value</i>.
   */
  static bool readConfigurationProperty(const std::string& name,
					std::string& value);

  /*! \brief Set the Ajax communication method.
   *
   * You may call this method only from your application constructor.
   *
   * The default method depends on your application type. For plain
   * applications, \link WApplication::XMLHttpRequest
   * XMLHttpRequest\endlink is used, while for embedded widget sets,
   * \link WApplication::DynamicScriptTag DynamicScriptTag\endlink is
   * used. The latter is less efficient, but has the benefit to allow
   * serving the application from a different server than the page
   * that hosts the embedded widgets.
   */
  void setAjaxMethod(AjaxMethod method);

  /*! \brief Get the Ajax communication method.
   *
   * \sa setAjaxMethod()
   */
  AjaxMethod ajaxMethod() const { return ajaxMethod_; }

  std::string javaScriptClass() { return javaScriptClass_; }

  WContainerWidget *domRoot() const { return domRoot_; }
  WContainerWidget *domRoot2() const { return domRoot2_; }

  std::string fixRelativeUrl(const std::string& url) const;
  static std::string resourcesUrl();

public slots:
  /*! \brief Exit the application.
   *
   * Signaling this slot will cause the application to end after the
   * current event is completed.
   *
   * By default, the current widget tree (including any modifications
   * still pending) is rendered, and the application is terminated. A
   * "-- Quited" is appended to the application title.
   *
   * You might want to make sure no more events can be received from
   * the user, by not having anything clickable, for example by
   * displaying only text. A better approach may be to redirect the
   * user to another page using redirect().
   */
  void quit();

public:
  /*! \brief Emitted when a too large post was received.
   *
   * The integer parameter is the request that was received in bytes.
   */
  Signal<int> requestTooLarge; 

protected:
  /*! \brief Notify an event to the application.
   *
   * This method is called by the event loop for propagating an event
   * to the application.
   *
   * You will rarely want to reimplement this method, unless you wish
   * to have a single point for exception handling. In that case, you should
   * call the baseclass implementation WApplication::notify(), and surround it
   * in your own try - catch block for those exceptions you wish to handle.
   *
   * Any uncaught exception will terminate the application.
   */
  virtual void notify(const WEvent& e);

private:
  typedef std::map<std::string, std::string> StateMap;

  WebSession            *session_;
  WString                title_;
  WContainerWidget      *widgetRoot_;
  WContainerWidget      *domRoot_;
  WContainerWidget      *timerRoot_;
  WContainerWidget      *dialogCover_;
  WContainerWidget      *dialogWindow_;
  WCssStyleSheet         styleSheet_;
  WMessageResourceBundle messageResourceBundle_;
  std::string            locale_;
  std::vector<Iframe *>  iframes_;
  bool                   titleChanged_;
  StateMap               state_;
  std::set<std::string>  statesChanged_;
  WServerPushResource   *serverPush_;
  std::string            javaScriptClass_;
  AjaxMethod             ajaxMethod_;

  struct ScriptLibrary {
    ScriptLibrary(const std::string& uri, const std::string& symbol);

    std::string uri, symbol;
    bool operator< (const ScriptLibrary& other) const;
    bool operator== (const ScriptLibrary& other) const;
  };

  std::vector<ScriptLibrary> scriptLibraries_;
  int                        scriptLibrariesAdded_;

  WContainerWidget      *domRoot2_;

  WWidget *useIframe();
  void releaseIframe(WWidget *iframe);

  struct StyleSheet {
    StyleSheet(const std::string& uri, const std::string& dependency);

    std::string uri, dependency;
  };

  std::vector<StyleSheet> styleSheets_;
  int                     styleSheetsAdded_;

  bool         quited_;

  friend class WebRenderer;
  friend class WebSession;
  friend class WebController;
  friend class EventSignalBase;
  friend class JavaScriptEvent;
  friend class WWidget;
  friend class WTimer;
  friend class WResource;
  friend class WFileUpload;
  friend class WInteractWidget;
  friend class WServerPushResource;
  friend class WViewWidget;
  friend class WDialog;

  typedef std::map<std::string, EventSignalBase *> SignalMap;
  SignalMap exposedSignals_;
  void addExposedSignal(EventSignalBase* signal);
  void removeExposedSignal(EventSignalBase* signal);
  EventSignalBase *decodeExposedSignal(const std::string& signalName) const;
  EventSignalBase *decodeExposedSignal(const std::string& objectId,
				       const std::string& name);
  const SignalMap& exposedSignals() const;

  /*
   * Exposed resources: resources that are encoded in the browser, and
   * may be streamed.
   */
  typedef std::map<std::string, WResource *> ResourceMap;
  ResourceMap exposedResources_;
  std::string addExposedResource(WResource *resource);
  void removeExposedResource(WResource *resource);
  WResource *decodeExposedResource(const std::string& resourceName) const;

  /*
   * Encoded objects: objects that are encoded for internal purposes:
   * They act as virtual pointers for referring to an object through
   * an event -- used for drag & drop.
   */
  typedef std::map<std::string, WObject *> ObjectMap;
  ObjectMap encodedObjects_;
  std::string encodeObject(WObject *object);
  WObject    *decodeObject(const std::string& objectId) const;

  bool isQuited() const { return quited_; }

  WContainerWidget *timerRoot() const { return timerRoot_; }
  WContainerWidget *dialogCover(bool create = true);
  WContainerWidget *dialogWindow(bool create = true);

  bool loadRsh();
  void setCurrentHistoryKey(const std::string& stateStr);
  std::string getCurrentHistoryKey() const;

  EventSignal<WResponseEvent> javaScriptResponse_;
  void handleJavaScriptResponse(WResponseEvent event);

  std::string afterLoadJavaScript_, beforeLoadJavaScript_,
    newBeforeLoadJavaScript_;

  std::string afterLoadJavaScript();
  std::string beforeLoadJavaScript();
  std::string newBeforeLoadJavaScript();

  bool exposeSignals_;

  void setExposeSignals(bool how) { exposeSignals_ = how; }
  bool exposeSignals() const { return exposeSignals_; }

  WEnvironment& env();
};

#ifdef WIN32
  #ifdef WTHTTP_STATIC
    #define WTCONNECTOR_API
  #else
    #ifdef wthttp_EXPORTS
      #define WTCONNECTOR_API __declspec(dllexport)
    #else
      #define WTCONNECTOR_API __declspec(dllimport)
    #endif
  #endif
#else
  #define WTCONNECTOR_API
#endif

/*! \brief Entry point for a %Wt application.
 *
 * This function must be called in the main of your application. The
 * createApplication parameter is a function pointer that creates a
 * %Wt application.
 */
extern int WTCONNECTOR_API WRun(int argc, char** argv,
				ApplicationCreator createApplication = 0);

extern void WTCONNECTOR_API
AddApplicationEntryPoint(ApplicationCreator createApplication,
			 const std::string& path = std::string());

extern void WTCONNECTOR_API
AddWidgetSetEntryPoint(ApplicationCreator createApplication,
		       const std::string& path);

/*! \brief Global constant for accessing the application instance.
 *
 * This is equivalent to WApplication::instance()
 */
#define wApp WApplication::instance()

}

#endif // WAPPLICATION_
