/*---------------------------------------------------------------
	FILE: SYNCH.h
	USE: See description below.

   Part of the MRPT Library
   ISA - Universidad de Malaga - http://www.isa.uma.es
  ---------------------------------------------------------------*/
#ifndef  SYNCH_H
#define  SYNCH_H

#include <MRPT/UTILS/utils_defs.h>
#include <MRPT/UTILS/CStream.h>

/*---------------------------------------------------------------
	Class
  ---------------------------------------------------------------*/
namespace UTILS
{
	/** This namespace provides multitask, synchronization utilities.
	 */
	namespace SYNCH
	{
		/** This class provides simple critical sections functionality.
		  * \sa CReadWriteCriticalSection
		  */
		class	CCriticalSection
		{
		private:
			void			*m_data;
			std::string		m_name;

		public:
			/** Constructor
			  */
			CCriticalSection(const char *name = NULL);

			/** Destructor
			  */
			~CCriticalSection();

			/** Enter
			  */
			void  enter();

			/** Leave
			  */
			void  leave();

			/** If set to a non-NULL value, debug messages regarding the calling threads IDs will be output.
			  */
			CStream		*m_debugOut;
		};

		/** This class provides critical sections functionality for two different access types: read and write
		  *  Any number of "read" threads can access the critical section simultaneously, while "write"
		  *   operations are strictly exclusive (only one "write" operation can be performed at once, not even simultanoeus "read" operations)
		  * \sa CCriticalSection
		  */
		class	CReadWriteCriticalSection
		{
		private:
			void	*m_data;

		public:
			/** Constructor
			  */
			CReadWriteCriticalSection();

			/** Destructor
			  */
			~CReadWriteCriticalSection();

			/** Enter for read
			  */
			void  enterRead();

			/** Leave read
			  */
			void  leaveRead();

			/** Enter for write
			  */
			void  enterWrite();

			/** Leave write
			  */
			void  leaveWrite();
		};

		/** This class provides a simple way of waiting for and signaling events.
		  */
		class	CEvent
		{
		private:
			void	*m_data;

		public:
			/** Constructor: set the initial signaled state of the event.
			  */
			CEvent( bool initialSignaled );

			/** Destructor
			  */
			~CEvent();

			/** Signal the event: the first waiting thread resumes execution (if no thread is waiting, the object keeps signaled)
			  */
			void  signal();

			/** Waits for the event to be signaled.
			  */
			void  wait();

			/** Manual reset of the event, without waiting to a signaled state (without effect if it is currently not signaled)
			  */
			void  reset();
		};

		/** A semaphore.
		  * The state of a semaphore object is signaled when its count is greater than zero,
		  *  and nonsignaled when its count is equal to zero. The initialCount parameter specifies
		  *  the initial count. Each time a waiting thread is released because of the semaphore's
		  *  signaled state, the count of the semaphore is decreased by one. Use the release function
		  *  to increment a semaphore's count by a specified amount. The count can never be less
		  *   than zero or greater than the value specified in the maxCount parameter.
		  */
		class CSemaphore
		{
		protected:
			void	*m_data;

        public:
            /** Creates a semaphore.
              */
            CSemaphore(
                unsigned int    initialCount,
                unsigned int    maxCount,
                const std::string &name=std::string("") );

            /** Destructor
              */
            ~CSemaphore();

            /** Blocks until the count of the semaphore to be non-zero.
              * \param timeout_ms The timeout in milliseconds, or set to zero to wait indefinidely.
              * \return true if the semaphore has been signaled, false on timeout or any other error.
              */
            bool waitForSignal( unsigned int timeout_ms = 0 );

            /** Increments the count of the semaphore by a given amount.
              */
            void release(unsigned int increaseCount = 1);

		};

	} // End of namespace

} // End of namespace

#endif
