/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "DLLInterface.h"
#include "Pimpl.h"

#include "CudaDevice.h"

#include "Rx.Core.Ex/RxImage.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx.LFR
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class CImageStacking_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Provides methods for stacking images within a given mode using a CUDA device.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API CImageStacking : public CPimpl<CImageStacking_Impl, Interfaces::EImageStacking::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Default constructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CImageStacking();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move constructor.
			/// </summary>
			///
			/// <param name="xImageStacking"> [in,out] The image stacking instance. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CImageStacking(CImageStacking&& xImageStacking);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Destructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			~CImageStacking();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the CUDA device that allocates the memory required for the stack operation and that runs the algorithm.
			/// </summary>
			///
			/// <param name="xCudaDevice"> The CUDA device. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void SetCudaDevice(const CCudaDevice& xCudaDevice);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the maximum number of image on the stack. Resets the stacking result if changed.
			/// </summary>
			///
			/// <param name="uMaxImageCount"> The maximum number of images. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void SetMaxImageCount(unsigned uMaxImageCount);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the stacking operation. Resets the stacking result if changed.
			/// </summary>
			///
			/// <param name="eStackingOp"> The stacking operation. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void SetStackingOperation(EImgStack::ID eStackingOp);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Adds an image to the stack. The image is uploaded to the CUDA device and processed.
			/// </summary>
			///
			/// <param name="pxImg"> [in] The image to add. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void AddImage(const Interop::Runtime28::IImage* pxImg);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Adds an image to the stack. The image is uploaded to the CUDA device and processed.
			/// </summary>
			///
			/// <param name="xImage"> [in] The image to add. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void AddImage(const CRxImage& xImage);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Queries if the stack is complete. This is the case if the stack is full.
			/// </summary>
			///
			/// <returns> True if complete, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool IsComplete() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the stacked image if the stacking has been finished.
			/// </summary>
			///
			/// <returns> The stacked image. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void DownloadStackedImage(CRxImage& xImage) const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Clears the stack by resetting the internal counter to zero.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Clear();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Clears the stack and frees the memory used by this stack. The memory is reallocated by calling AddImage.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Free();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move assignment operator.
			/// </summary>
			///
			/// <param name="xImageStacking"> [in,out] The image stacking instance. </param>
			///
			/// <returns> The instance. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CImageStacking& operator=(CImageStacking&& xImageStacking);
		};
	}
}
