// 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/WObject>
#include <Wt/WSignal>
#include <Wt/WEvent>

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 the WTimer class, 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. To create a
 * timer that will fire only once, use setSingleShot(). There is also
 * a convience static method singleShot()
 *
 * 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.
 */
class WT_API WTimer : public WObject
{
public:
  /*! \brief Construct a new timer with the given parent.
   */
  WTimer(WObject *parent = 0);

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

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

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

  /*! \brief Return 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 Configure this timer to fire only once.
   *
   * A Timer is by default not single shot, and will fire continuously,
   * until it is stopped.
   *
   * \sa singleShot()
   */
  void setSingleShot(bool singleShot);

  /*! \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, SLOT(this, MyClass::doSome));
   * \endcode
   */
  template <class T, class V>
  static void singleShot(int msec, T *receiver, void (V::*method)());

private:
  WTimerWidget *timerWidget_;

public slots:
  /*! \brief Start 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 Stop the timer.
   */
  void stop();

public:
  /*! \brief Signal emitted when the timer timeouts.
   */
  EventSignal<void> timeout;

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

  Time *timeout_;

  void gotTimeout();

  void setSelfDestruct();
  int getRemainingInterval() const;

  friend class WTimerWidget;
};

template <class T, class V>
void WTimer::singleShot(int msec, T *receiver, void (V::*method)())
{
  WTimer *timer = new WTimer();
  timer->setSingleShot(true);
  timer->setInterval(msec);
  timer->setSelfDestruct();
  timer->timeout.connect(receiver, method);
  timer->start();
}

}

#endif // WTIMER_H_
