//-----------------------------------------------------------------------------
//
//	Wait.h
//
//	Cross-platform abstract base class for objects we 
//	want to be able to wait for.
//
//	Copyright (c) 2010 Mal Lansell <mal@lansell.org>
//	All rights reserved.
//
//	SOFTWARE NOTICE AND LICENSE
//
//	This file is part of OpenZWave.
//
//	OpenZWave is free software: you can redistribute it and/or modify
//	it under the terms of the GNU Lesser General Public License as published
//	by the Free Software Foundation, either version 3 of the License,
//	or (at your option) any later version.
//
//	OpenZWave is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public License
//	along with OpenZWave.  If not, see <http://www.gnu.org/licenses/>.
//
//-----------------------------------------------------------------------------
#ifndef _Wait_H
#define _Wait_H

#include <list>
#include "platform/Ref.h"

namespace OpenZWave
{
	namespace Internal
	{
		namespace Platform
		{
			class WaitImpl;

			/** \brief Platform-independent definition of Wait objects.
			 * \ingroup Platform
			 */
			class Wait: public Ref
			{
					friend class WaitImpl;
					friend class ThreadImpl;

				public:
					enum
					{
						Timeout_Immediate = 0,
						Timeout_Infinite = -1
					};

					typedef void (*pfnWaitNotification_t)(void* _context);

					/**
					 * Add a watcher to our object.  The watcher will be triggered
					 * by the derived class, when it enters a certain state.
					 * \param _callback pointer to the function that will be called when the wait is over.
					 * \param _context pointer to custom data that will be sent with the callback.
					 */
					void AddWatcher(pfnWaitNotification_t _callback, void* _context);

					/**
					 * Remove a watcher from our object.  Both the _callback and _context pointers 
					 * must match those used in a previous call to AddWatcher.
					 * \param _callback pointer to the function that will be called when the wait is over.
					 * \param _context pointer to custom data that will be sent with the callback.
					 */
					void RemoveWatcher(pfnWaitNotification_t _callback, void* _context);

					/**
					 * Wait for a single object to become signalled.
					 * \param _object pointer to the object to wait on.
					 * \param _timeout optional maximum time to wait.  Defaults to -1, which means wait forever.
					 * \return zero if the object was signalled, -1 if the wait timed out.
					 */
					static int32 Single(Wait* _object, int32 _timeout = -1)
					{
						return Multiple(&_object, 1, _timeout);
					}

					/**
					 * Wait for one of multiple objects to become signalled.  If more than one object is in
					 * a signalled state, the lowest array index will be returned.
					 * \param _objects array of pointers to objects to wait on.
					 * \param _numObjects number of objects in the array.
					 * \param _timeout optional maximum time to wait.  Defaults to -1, which means wait forever.
					 * \return index into the array of the object that was signalled, -1 if the wait timed out.
					 */
					static int32 Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout = -1);

				protected:
					Wait();
					virtual ~Wait();

					/**
					 * Notify the watchers that the object is signalled.
					 */
					void Notify();

					/**
					 * Test whether an object is signalled.
					 */
					virtual bool IsSignalled() = 0;

				private:
					Wait(Wait const&);					// prevent copy
					Wait& operator =(Wait const&);		// prevent assignment

					WaitImpl* m_pImpl;					// Pointer to an object that encapsulates the platform-specific implementation of a Wait object.
			};
		} // namespace Platform
	} // namespace Internal
} // namespace OpenZWave

#endif //_Wait_H

