/*! \file
* \brief Task adaptors.
*
* This file contains adaptors for task function objects.
*
* Copyright (c) 2005-2007 Philipp Henkel
*
* Use, modification, and distribution are  subject to the
* Boost Software License, Version 1.0. (See accompanying  file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* http://threadpool.sourceforge.net
*
*/


#ifndef THREADPOOL_TASK_ADAPTERS_HPP_INCLUDED
#define THREADPOOL_TASK_ADAPTERS_HPP_INCLUDED


#include <boost/smart_ptr.hpp>
#include <boost/function.hpp>
#include <boost/thread.hpp>


namespace boost { namespace threadpool
{

  /*! \brief Standard task function object.
  *
  * This function object wraps a nullary function which returns void.
  * The wrapped function is invoked by calling the operator ().
  *
  * \see boost function library
  *
  */ 
  typedef function0<void> task_func;




  /*! \brief Prioritized task function object. 
  *
  * This function object wraps a task_func object and binds a priority to it.
  * prio_task_funcs can be compared using the operator < which realises a partial ordering.
  * The wrapped task function is invoked by calling the operator ().
  *
  * \see prio_scheduler
  *
  */ 
  class prio_task_func
  {
  private:
    unsigned int m_priority;  //!< The priority of the task's function.
    task_func m_function;     //!< The task's function.

  public:
    typedef void result_type; //!< Indicates the functor's result type.

  public:
    /*! Constructor.
    * \param priority The priority of the task.
    * \param function The task's function object.
    */
    prio_task_func(unsigned int const priority, task_func const & function)
      : m_priority(priority)
      , m_function(function)
    {
    }

    /*! Executes the task function.
    */
    void operator() (void) const
    {
      if(m_function)
      {
        m_function();
      }
    }

    /*! Comparison operator which realises a partial ordering based on priorities.
    * \param rhs The object to compare with.
    * \return true if the priority of *this is less than right hand side's priority, false otherwise.
    */
    bool operator< (const prio_task_func& rhs) const
    {
      return m_priority < rhs.m_priority; 
    }

  };  // prio_task_func



 




  /*! \brief Looped task function object. 
  *
  * This function object wraps a boolean thread function object.
  * The wrapped task function is invoked by calling the operator () and it is executed in regular 
  * time intervals until false is returned. The interval length may be zero.
  * Please note that a pool's thread is engaged as long as the task is looped.
  *
  */ 
  class looped_task_func
  {
  private:
    function0<bool> m_function;   //!< The task's function.
    unsigned int m_break_s;              //!< Duration of breaks in seconds.
    unsigned int m_break_ns;             //!< Duration of breaks in nano seconds.

  public:
    typedef void result_type; //!< Indicates the functor's result type.

  public:
    /*! Constructor.
    * \param function The task's function object which is looped until false is returned.
    * \param interval The minimum break time in milli seconds before the first execution of the task function and between the following ones.
    */
    looped_task_func(function0<bool> const & function, unsigned int const interval = 0)
      : m_function(function)
    {
      m_break_s  = interval / 1000;
      m_break_ns = (interval - m_break_s * 1000) * 1000 * 1000;
    }

    /*! Executes the task function.
    */
    void operator() (void) const
    {
      if(m_function)
      {
        if(m_break_s > 0 || m_break_ns > 0)
        { // Sleep some time before first execution
          xtime xt;
#if BOOST_VERSION < 105000
          xtime_get(&xt, TIME_UTC);
#else
          xtime_get(&xt, TIME_UTC_);
#endif  // if BOOST_VERSION < 105000
          xt.nsec += m_break_ns;
          xt.sec += m_break_s;
          thread::sleep(xt); 
        }

        while(m_function())
        {
          if(m_break_s > 0 || m_break_ns > 0)
          {
            xtime xt;
#if BOOST_VERSION < 105000
            xtime_get(&xt, TIME_UTC);
#else
            xtime_get(&xt, TIME_UTC_);
#endif  // if BOOST_VERSION < 105000
            xt.nsec += m_break_ns;
            xt.sec += m_break_s;
            thread::sleep(xt); 
          }
          else
          {
            thread::yield(); // Be fair to other threads
          }
        }
      }
    }

  }; // looped_task_func


} } // namespace boost::threadpool

#endif // THREADPOOL_TASK_ADAPTERS_HPP_INCLUDED

