// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef BASE_TIMER_H_
#define BASE_TIMER_H_

#include <math.h>
#include <windows.h>

#include <queue>
#include <vector>

#include "base/basictypes.h"
#include "base/time.h"

// Timer/TimerManager are objects designed to help setting timers.
// Goals of TimerManager:
// - have only one Windows system timer for all app timer functionality
// - work around bugs with timers firing arbitrarily earlier than specified
// - provide the ability to run timers even if the application is in a
//   windows modal app loop.

class TimerManager;
class Task;
class MessageLoop;

class Timer {
 public:
  Timer(int delay, Task* task, bool repeating);

  Task* task() const { return task_; }
  void set_task(Task* task) { task_ = task; }

  int current_delay() const {
    // Be careful here.  Timers have a precision of microseconds,
    // but this API is in milliseconds.  If there are 5.5ms left,
    // should the delay be 5 or 6?  It should be 6 to avoid timers
    // firing early.  Implement ceiling by adding 999us prior to
    // conversion to ms.
    double delay = ceil((fire_time_ - Time::Now()).InMillisecondsF());
    return static_cast<int>(delay);
  }

  const Time &fire_time() const { return fire_time_; }

  bool repeating() const { return repeating_; }

  // Update (or fill in) creation_time_, and calculate future fire_time_ based
  // on current time plus delay_.
  void Reset();

  int id() const { return timer_id_; }

 protected:
  // Protected (rather than private) so that we can access from unit tests.

  // The time when the timer should fire.
  Time fire_time_;

 private:
  // A sequence number for all allocated times (used to break ties when
  // comparing times in the TimerManager, and assure FIFO execution sequence).
  static int32 timer_id_counter_;

  // The task that is run when this timer fires.
  Task* task_;

  // Timer delay in milliseconds.
  int delay_;

  // A monotonically increasing timer id.  Used
  // for ordering two timers which have the same
  // timestamp in a FIFO manner.
  int timer_id_;

  // Whether or not this timer repeats.
  const bool repeating_;

  // The tick count when the timer was "created". (i.e. when its current
  // iteration started.)
  Time creation_time_;

  DISALLOW_EVIL_CONSTRUCTORS(Timer);
};

class TimerComparison {
 public:
  bool operator() (const Timer* t1, const Timer* t2) const {
    const Time& f1 = t1->fire_time();
    const Time& f2 = t2->fire_time();
    // If the two timers have the same delay, revert to using
    // the timer_id to maintain FIFO ordering.
    if (f1 == f2) {
      // Gracefully handle wrap as we try to return (t1->id() > t2->id());
      int delta = t1->id() - t2->id();
      // Assuming the delta is smaller than 2**31, we'll always get the right
      // answer (in terms of sign of delta).
      return delta > 0;
    }
    return f1 > f2;
  }
};

// Subclass priority_queue to provide convenient access to removal from this
// list.
//
// Terminology: The "pending" timer is the timer at the top of the queue,
//              i.e. the timer whose task needs to be Run next.
class TimerPQueue : public std::priority_queue<Timer*,
                                               std::vector<Timer*>,
                                               TimerComparison> {
 public:
  // Removes |timer| from the queue.
  void RemoveTimer(Timer* timer);

  // Returns true if the queue contains |timer|.
  bool ContainsTimer(const Timer* timer) const;
};

// There is one TimerManager per thread, owned by the MessageLoop.
// Timers can either be fired directly by the MessageLoop, or by
// SetTimer and a WM_TIMER message.  The advantage of the former
// is that we can make timers fire significantly faster than the 10ms
// granularity provided by SetTimer().  The advantage of SetTimer()
// is that modal message loops which don't run our MessageLoop
// code will still be able to process WM_TIMER messages.
//
// Note:  TimerManager is not thread safe.  You cannot set timers
//        onto a thread other than your own.
class TimerManager {
 public:
  TimerManager();
  ~TimerManager();

  // Create and start a new timer. |task| is owned by the caller, as is the
  // timer object that is returned.
  Timer* StartTimer(int delay, Task* task, bool repeating);

  // Flag indicating whether the timer manager should use the OS
  // timers or not.  Default is true.  MessageLoops which are not reliably
  // called due to nested windows message loops should set this to
  // true.
  bool use_native_timers() { return use_native_timers_; }
  void set_use_native_timers(bool value) { use_native_timers_ = value; }

  // Starts a timer.  This is a no-op if the timer is already started.
  void StartTimer(Timer* timer);

  // Stop a timer.  This is a no-op if the timer is already stopped.
  void StopTimer(Timer* timer);

  // Reset an existing timer, which may or may not be currently in the queue of
  // upcoming timers.  The timer's parameters are unchanged; it simply begins
  // counting down again as if it was just created.
  void ResetTimer(Timer* timer);

  // Returns true if |timer| is in the queue of upcoming timers.
  bool IsTimerRunning(const Timer* timer) const;

  // Run some small number of timers.
  // Returns true if it runs a task, false otherwise.
  bool RunSomePendingTimers();

  // The number of milliseconds remaining until the pending timer (top of the
  // pqueue) needs to be fired. Returns -1 if no timers are pending.
  int GetCurrentDelay();

  // A handler for WM_TIMER messages.
  // If a task is not running currently, it runs some timer tasks (if there are
  // some ready to fire), otherwise it just updates the WM_TIMER to be called
  // again (hopefully when it is allowed to run a task).
  int MessageWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);

  // Return cached copy of MessageLoop::current().
  MessageLoop* message_loop();

#ifdef UNIT_TEST
  // For testing only, used to simulate broken early-firing WM_TIMER
  // notifications by setting arbitrarily small delays in SetTimer.
  void set_use_broken_delay(bool use_broken_delay) {
    use_broken_delay_ = use_broken_delay;
  }
#endif

 protected:
  // Peek at the timer which will fire soonest.
  Timer* PeekTopTimer();

 private:
  // Update our Windows WM_TIMER to match our most immediately pending timer.
  void UpdateWindowsWmTimer();

  // Retrieve the Message Window that handles WM_TIMER messages from the
  // system.
  HWND GetMessageHWND();

  TimerPQueue timers_;

  bool use_broken_delay_;

  HWND message_hwnd_;

  // Flag to enable/disable use of native timers.
  bool use_native_timers_;

  // A lazily cached copy of MessageLoop::current.
  MessageLoop* message_loop_;

  DISALLOW_EVIL_CONSTRUCTORS(TimerManager);
};

// A simple wrapper for the Timer / TimerManager API.  This is a helper class.
// Use OneShotTimer or RepeatingTimer instead.
class SimpleTimer {
 public:
  // Stops the timer.
  ~SimpleTimer();

  // Call this method to explicitly start the timer.  This is a no-op if the
  // timer is already running.
  void Start();

  // Call this method to explicitly stop the timer.  This is a no-op if the
  // timer is not running.
  void Stop();

  // Returns true if the timer is running (i.e., not stopped).
  bool IsRunning() const;

  // Short-hand for calling Stop and then Start.
  void Reset();

  // Get/Set the task to be run when this timer expires.  NOTE: The caller of
  // set_task must be careful to ensure that the old task is properly deleted.
  Task* task() const { return timer_.task(); }
  void set_task(Task* task) {
    timer_.set_task(task);
    owns_task_ = true;
  }

  // Sets the task, but marks it so it shouldn't be deleted by the SimpleTimer.
  void set_unowned_task(Task* task) {
    timer_.set_task(task);
    owns_task_ = false;
  }

 protected:
  SimpleTimer(TimeDelta delay, Task* task, bool repeating);

 private:
  Timer timer_;

  // Whether we need to clean up the Task* object for this Timer when
  // we are deallocated. Defaults to true.
  bool owns_task_;

  DISALLOW_EVIL_CONSTRUCTORS(SimpleTimer);
};

// A simple, one-shot timer.  The task is run after the specified delay once
// the Start method is called.  The task is deleted when the timer object is
// destroyed.
class OneShotTimer : public SimpleTimer {
 public:
  // The task must be set using set_task before calling Start.
  explicit OneShotTimer(TimeDelta delay)
      : SimpleTimer(delay, NULL, false) {
  }
  // If task is null, then it must be set using set_task before calling Start.
  OneShotTimer(TimeDelta delay, Task* task)
      : SimpleTimer(delay, task, false) {
  }
 private:
  DISALLOW_EVIL_CONSTRUCTORS(OneShotTimer);
};

// A simple, repeating timer.  The task is run at the specified interval once
// the Start method is called.  The task is deleted when the timer object is
// destroyed.
class RepeatingTimer : public SimpleTimer {
 public:
  // The task must be set using set_task before calling Start.
  explicit RepeatingTimer(TimeDelta interval)
      : SimpleTimer(interval, NULL, true) {
  }
  // If task is null, then it must be set using set_task before calling Start.
  RepeatingTimer(TimeDelta interval, Task* task)
      : SimpleTimer(interval, task, true) {
  }
 private:
  DISALLOW_EVIL_CONSTRUCTORS(RepeatingTimer);
};

#endif  // BASE_TIMER_H_