// Reactor_Timer_Queue_Test.cpp,v 4.8 2004/06/14 11:33:36 jwillemsen Exp

// ============================================================================
// = LIBRARY
//    examples
//
// = FILENAME
//    Reactor_Timer_Queue_Test
//
// = DESCRIPTION
//    This example tests the timer queue mechanism of ACE_Reactor.
//
// = AUTHOR
//    Nanbor Wang <nw1@cs.wustl.edu> and
//    Sergio Flores-Gaitan <sergio@cs.wustl.edu>
//
// ============================================================================

#include "ace/OS_NS_sys_time.h"
#include "ace/Thread_Manager.h"
#include "ace/Select_Reactor.h"
#include "ace/Reactor.h"
#include "ace/Timer_Heap.h"

#include "Driver.h"
#include "Reactor_Timer_Queue_Test.h"

#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class Timer_Queue_Test_Driver <ACE_Timer_Heap, Input_Handler, Input_Handler::ACTION>;
template class Command<Input_Handler, Input_Handler::ACTION>;
#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
#pragma instantiate Timer_Queue_Test_Driver <ACE_Timer_Heap, Input_Handler, Input_Handler::ACTION>
#pragma instantiate Command<Input_Handler, Input_Handler::ACTION>
#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */

ACE_RCSID(Timer_Queue, Reactor_Timer_Queue_Test, "Reactor_Timer_Queue_Test.cpp,v 4.8 2004/06/14 11:33:36 jwillemsen Exp")

void
Reactor_Timer_Handler::set_timer_id (long tid)
{
  this->tid_ = tid;
}

int
Reactor_Timer_Handler::handle_timeout (const ACE_Time_Value &tv,
                                       const void *)
{
  // Macro to avoid "warning: unused parameter" type warning.
  ACE_UNUSED_ARG (tv);

  ACE_Time_Value txv = ACE_OS::gettimeofday ();
  ACE_DEBUG ((LM_DEBUG,
              "\nTimer #%d fired at %d.%06d (%T)!\n",
              this->tid_,
              txv.sec (),
              txv.usec ()));
  delete this;

  return 0;
}

Input_Handler::Input_Handler (ACE_Timer_Queue *tq,
                              Reactor_Timer_Queue_Test_Driver &timer_queue_driver)
  : done_ (0),
    driver_ (timer_queue_driver)
{
  this->tq_ = tq;
}

int
Input_Handler::done (void)
{
  return this->done_;
}

int
Input_Handler::schedule_timer (void *argument)
{
  int delay = *(int *) argument;
  Reactor_Timer_Handler *th;
  long tid;

  th = new Reactor_Timer_Handler;
  if (th != 0)
    {
      tid = this->reactor ()->schedule_timer (th,
                                              0,
                                              ACE_Time_Value (0, delay));
      if (tid == -1)
        ACE_DEBUG ((LM_DEBUG,
                    "Unable to schedule timer\n"));
      else
        {
          ACE_DEBUG ((LM_DEBUG,
                      "Timer #%d schedule to fire after %d usec from now.\n",
                      tid,
                      delay));
          th->set_timer_id (tid);
        }
    }
  else
    ACE_ERROR_RETURN ((LM_ERROR,
                       "not enough memory?\n"),
                      -1);
  return tid;
}

int
Input_Handler::cancel_timer (void *argument)
{
  int id = *(int *) argument;
  return this->reactor ()->cancel_timer (id);
}

int
Input_Handler::shutdown_timer (void *argument)
{
  // Macro to avoid "warning: unused parameter" type warning.
  ACE_UNUSED_ARG (argument);

  this->done_ = 1;
  ACE_DEBUG ((LM_DEBUG,
              "Shutting down event loop\n"));
  return -1;
}

int
Input_Handler::list_timer (void *argument)
{
  // Macro to avoid "warning: unused parameter" type warning.
  ACE_UNUSED_ARG (argument);

  ACE_Timer_Queue_Iterator &iter = this->tq_->iter ();
  ACE_DEBUG ((LM_DEBUG,
              "\n\nTimers in queue:\n"));

  for (; !iter.isdone (); iter.next ())
    {
      ACE_Timer_Node *tn = iter.item ();
      ACE_DEBUG ((LM_DEBUG, "Timer #%d: %d.%06d\n",
                  tn->get_timer_id (),
                  tn->get_timer_value ().sec (),
                  tn->get_timer_value ().usec ()));
    }
  return 0;
}

int
Input_Handler::handle_input (ACE_HANDLE)
{
  return driver_.get_next_request ();
}

Reactor_Timer_Queue_Test_Driver::Reactor_Timer_Queue_Test_Driver (void)
  : thandler_ (&timer_queue_, *this)
{
}

Reactor_Timer_Queue_Test_Driver::~Reactor_Timer_Queue_Test_Driver (void)
{
}

int
Reactor_Timer_Queue_Test_Driver::display_menu (void)
{
  static char menu[] =
    "\n*****\n"
    "1) Schedule timer <usec>\n"
    "2) Cancel timer <id>\n"
    "3) List all timers\n"
    "4) Shutdown program\n"
    "Enter selection:";

  ACE_DEBUG ((LM_DEBUG,
              "%s",
              menu));
  return 0;
}

int
Reactor_Timer_Queue_Test_Driver::init (void)
{
  typedef Command<Input_Handler, Input_Handler::ACTION> CMD;

  // initialize <Command>s with their corresponding <Input_Handler>  methods.
  ACE_NEW_RETURN (schedule_cmd_,
                  CMD (thandler_, &Input_Handler::schedule_timer),
                  -1);

  ACE_NEW_RETURN (cancel_cmd_,
                  CMD (thandler_, &Input_Handler::cancel_timer),
                  -1);

  ACE_NEW_RETURN (list_cmd_,
                  CMD (thandler_, &Input_Handler::list_timer),
                  -1);

  ACE_NEW_RETURN (shutdown_cmd_,
                  CMD (thandler_, &Input_Handler::shutdown_timer),
                  -1);

  ACE_Reactor::instance ()->timer_queue (&timer_queue_);

  ACE_Event_Handler::register_stdin_handler (&thandler_,
                               			ACE_Reactor::instance (),
                               			ACE_Thread_Manager::instance ());

  // print the menu of options.
  this->display_menu ();

  return 0;
}

// run test was overrun due to the reactive way of handling input.

int
Reactor_Timer_Queue_Test_Driver::run_test (void)
{
  ACE_DEBUG ((LM_DEBUG,
              "TIMER TEST STARTED\n"));

  this->init ();

  // Run until we say stop.
  while (thandler_.done () == 0)
    ACE_Reactor::instance ()->handle_events ();

  ACE_DEBUG ((LM_DEBUG,
              "TIMER TEST ENDED\n"));
  return 0;
}
