/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "DLLInterface.h"
#include "Pimpl.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class CImageQueue_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	A bounded queue that uses the move semantics and that is thread safe.
		/// </summary>
		///
		/// <typeparam name="TValue"> The value type. This type requires a move constructor and a move assignment operator. </typeparam>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API CImageQueue : public CPimpl<CImageQueue_Impl, Interfaces::EImageQueue::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Default constructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CImageQueue();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move constructor.
			/// </summary>
			///
			/// <param name="xImageQueue"> [in,out] The native image queue. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CImageQueue(CImageQueue&& xImageQueue);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Destructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			~CImageQueue();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the maximum queue size and clears the queue.
			/// </summary>
			///
			/// <param name="nMaxQueueSize">	 The maximum queue size. </param>
			/// <param name="bOverwriteEnabled"> True to enable overwriting of the oldest queue element if the queue is full on MoveIn. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Initialize(size_t nMaxQueueSize, bool bOverwriteEnabled);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Clears this object to its blank/initial state.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Clear();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Moves the given image at the end of the queue. This signals the not-empty-event.
			/// </summary>
			///
			/// <param name="xImage"> [in,out] The image to move into the queue. May be invalid after this call. </param>
			///
			/// <returns> True if it succeeds, false if the queue is full and overwrite is disabled. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool MoveIn(Rx::CRxImage&& xImage);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Moves the first image out of the queue. This resets the not-empty-event if the queue is now empty.
			/// </summary>
			///
			/// <param name="xImage"> [out] The first image of the queue. </param>
			///
			/// <returns> True if it succeeds, false if the queue is empty. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool MoveOut(Rx::CRxImage& xImage);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Query if this queue is empty.
			/// </summary>
			///
			/// <returns> True if empty, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool IsEmpty() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the current queue size.
			/// </summary>
			///
			/// <returns> The current queue size. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			size_t GetSize() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the free size. This is the maximum queue size minus the current queue size.
			/// </summary>
			///
			/// <returns> The free size. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			size_t GetFreeSize() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the maximum queue size.
			/// </summary>
			///
			/// <returns> The maximum queue size. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			const size_t& GetMaxQueueSize() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the overwrite enabled flag.
			/// </summary>
			///
			/// <returns> The overwrite enabled flag. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool GetOverwriteEnabled() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Waits.
			/// </summary>
			///
			/// <param name="iMilliseconds"> (Optional) The maximal waiting time in milliseconds. if iMilliseconds is set to -1 the time is
			/// 							 set to infinite. </param>
			///
			/// <returns> True if it succeeds, false if it fails. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool WaitForNotEmpty(int iMilliseconds = -1) const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the windows handle of the not empty event. This can be used in functions like WaitForSingleObject.
			/// </summary>
			///
			/// <returns> The not empty event handle. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void* GetNotEmptyEventWin32Handle() const;

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move assignment operator.
			/// </summary>
			///
			/// <param name="xImageQueue"> [in,out]The image queue instance. </param>
			///
			/// <returns> The instance. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CImageQueue& operator=(CImageQueue&& xImageQueue);
		};
	}
}
