// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TIMEOUT_KERNEl_ABSTRACT_
#ifdef DLIB_TIMEOUT_KERNEl_ABSTRACT_

#include "../threads.h"

namespace dlib
{

    class timeout 
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object provides a simple way to implement a timeout.  An example will
                make its use clear.  Suppose we want to read from a socket but we want to
                terminate the connection if the read takes longer than 10 seconds.  This
                could be accomplished as follows:

                connection* con = a connection from somewhere;
                {
                    // setup a timer that will call con->shutdown() in 10 seconds
                    timeout t(*con,&connection::shutdown,10000); 
                    // Now call read on the connection.  If this call to read() takes more
                    // than 10 seconds then the t timeout will trigger and shutdown the
                    // connection.  If read completes in less than 10 seconds then the t
                    // object will be destructed on the next line due to the } and then the
                    // timeout won't trigger.
                    con->read(buf,100);
                }

                
                Alternatively, if you have a compiler capable of using C++11 lambda
                functions, you can use a syntax like this:
                {
                    timeout t([con](){ con->shutdown(); }, 10000);
                    con->read(buf,100);
                }

                More generally, you can use this with things other than sockets.  For
                example, the following statement will print "Hello world!" after 1000ms:
                    timeout t([](){ cout << "Hello world!" << endl; },  1000);



            THREAD SAFETY
                All methods of this class are thread safe. 
        !*/

    public:

        template <
            typename T
            >
        timeout (
            T callback_function,
            unsigned long ms_to_timeout
        );
        /*!
            requires
                - callback_function does not throw
            ensures                
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - callback_function() will be called in ms_to_timeout milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T
            >
        timeout (  
            T& object,
            void (T::*callback_function)(),
            unsigned long ms_to_timeout
        );
        /*!
            requires
                - callback_function does not throw
            ensures                
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)() will be called in ms_to_timeout 
                      milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T,
            typename U
            >
        timeout (  
            T& object,
            void (T::*callback_function)(U callback_function_argument),
            unsigned long ms_to_timeout,
            U callback_function_argument
        );
        /*!
            requires
                - callback_function does not throw
            ensures                
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)(callback_function_argument) will be 
                      called in ms_to_timeout milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T
            >
        timeout (  
            T& object,
            int (T::*callback_function)(),
            unsigned long ms_to_timeout
        );
        /*!
            requires
                - callback_function does not throw
            ensures                
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)() will be called in ms_to_timeout 
                      milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T,
            typename U
            >
        timeout (  
            T& object,
            int (T::*callback_function)(U callback_function_argument),
            unsigned long ms_to_timeout,
            U callback_function_argument
        );
        /*!
            requires
                - callback_function does not throw
            ensures                
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)(callback_function_argument) will be 
                      called in ms_to_timeout milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~timeout (
        );
        /*!
            requires
                - is not called from inside the callback_function given to the
                  constructor.
            ensures
                - any resources associated with *this have been released
                - if (the callback_function hasn't been called yet) then
                    - the callback_function specified in the constructor will not be called
        !*/

    private:

        // restricted functions
        timeout(const timeout&);        // copy constructor
        timeout& operator=(const timeout&);    // assignment operator

    };    

}

#endif // DLIB_TIMEOUT_KERNEl_ABSTRACT_