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

#include <Wt/WApplication>
#include <Wt/WObject>
#include <Wt/WSignal>
#include <Wt/WEvent>

#ifndef WT_TARGET_JAVA
#include <boost/bind.hpp>
#endif // WT_TARGET_JAVA

namespace Wt {

class WTimerWidget;
class Time;

/*! \class WTimer Wt/WTimer Wt/WTimer
 *  \brief A utility class which provides timer signals and single-shot timers.
 *
 * To use a timer, create a %WTimer instance, set the timer
 * interval using setInterval() and connect a slot to the timeout signal.
 * Then, start the timer using start(). An active timer may be cancelled
 * at any time using stop().
 *
 * By default, a timer will continue to generate events until you
 * stop() it. To create a timer that will fire only once, use
 * setSingleShot(). 
 * \if cpp
 * There is also a convience static method singleShot().
 * \endif 
 *
 * When connecting stateless slot implementations to the timeout
 * signal, these stateless slot implementations will be used as for
 * any other signal (when Ajax is available).
 *
 * In clients without (enabled) JavaScript support, the minimum
 * resolution of the timer is one second (1000 milli-seconds), and it
 * is probably wise to use timers sparingly.
 *
 * A WTimer is only usable inside of a %Wt event loop.
 * \if cpp
 * If you want to create a timer outside the %Wt event loop, take a look at asio deadline_timer or steady_timer.
 * \else
 * If you want to create a timer outside the %Wt event loop, take a look at {javadoclink java.util.Timer}.
 * \endif
 * 
 * \if cpp
 * Timers are one way to provide updates of a web page without the
 * user generating an event. Alternatively you may consider
 * server-initiated updates, see WApplication::enableUpdates().
 * \endif
 *
 * \if cpp
 * Usage example:
 * \code
 * // setup a timer which calls MyClass::timeout() every 2 seconds, until timer->stop() is called.
 * Wt::WTimer *timer = new Wt::WTimer();
 * timer->setInterval(2000);
 * timer->timeout().connect(this, &MyClass::timeout);
 * timer->start();
 * \endcode
 * \endif
 */
class WT_API WTimer : public WObject
{
public:
  /*! \brief Construct a new timer with the given parent.
   */
  WTimer(WObject *parent = 0);

  /*! \brief Destuctor.
   */
  ~WTimer();

  /*! \brief Returns the interval (msec).
   */
  int interval() const { return interval_; }

  /*! \brief Sets the interval (msec).
   */
  void setInterval(int msec);

  /*! \brief Returns if the timer is running.
   */
  bool isActive() const { return active_; }

  /*! \brief Is this timer set to fire only once.
   */
  bool isSingleShot() const { return singleShot_; }

  /*! \brief Configures this timer to fire only once.
   *
   * A Timer is by default not single shot, and will fire continuously,
   * until it is stopped.
   *
   * \if cpp
   * \sa singleShot()
   * \endif
   */
  void setSingleShot(bool singleShot);

#ifndef WT_TARGET_JAVA
  /*! \brief This static function calls a slot after a given time interval.
   *
   * For example, the following code will call this->doSome() after 2
   * seconds: 
   * \code
   *   WTimer::singleShot(2000, this, &MyClass::doSome);
   * \endcode
   */
  template <class T, class V>
  static void singleShot(int msec, T *receiver, void (V::*method)());

  /*! \brief This static function calls a function after a given time interval.
   *
   * This variant of the overloaded singleShot() method supports a
   * template function object (which supports operator ()).
   */
  template <class F>
  static void singleShot(int msec, const F& f);
#endif // WT_TARGET_JAVA

  /*! \brief Starts the timer.
   *
   * The timer will be isActive(), until either the interval has
   * elapsed, after which the timeout signal is activated,
   * or until stop() is called.
   */
  void start();

  /*! \brief Stops the timer.
   *
   * You may stop the timer during its timeout(), or cancel a running timer
   * at any other time.
   *
   * \sa start()
   */
  void stop();

  /*! \brief %Signal emitted when the timer timeouts.
   *
   * The %WMouseEvent does not provide any meaningful information but is
   * an implementation artefact.
   */
  EventSignal<WMouseEvent>& timeout();

private:
  WTimerWidget *timerWidget_;

  bool singleShot_;
  bool selfDestruct_;
  int  interval_;
  bool active_;
  bool timeoutConnected_;

  Time *timeout_;

  void gotTimeout();

  void setSelfDestruct();
  int getRemainingInterval() const;

  friend class WTimerWidget;
};

#ifndef WT_TARGET_JAVA
template <class T, class V>
void WTimer::singleShot(int msec, T *receiver, void (V::*method)())
{
  singleShot(msec, boost::bind(method, receiver));
}

template <class F>
void WTimer::singleShot(int msec, const F& f)
{
  WTimer *timer = new WTimer(WApplication::instance());
  timer->setSingleShot(true);
  timer->setInterval(msec);
  timer->setSelfDestruct();
  timer->start();
  timer->timeout().connect(f);
}
#endif // WT_TARGET_JAVA

}

#endif // WTIMER_H_
