/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "DLLInterface.h"

#include "Pimpl.h"

#include "Rx.Interop.Runtime30/Rx.ThreeStates.h"
#include "Rx.Interop.Runtime30/TriggerModes.h"
#include "Rx.Interop.Runtime30/CameraProperties.h"
#include "Rx.Interop.Runtime30/Rx.Camera.SetIpCodes.h"

#include "Rx.Core/RxString.h"
#include "Rx.Core.Ex/RxArrayInt.h"
#include "Rx.Core.Ex/RxImage.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx.LFR
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class CCamera_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	A camera.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API CCamera : public CPimpl<CCamera_Impl, Interfaces::ECamera::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Constructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CCamera();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move constructor.
			/// </summary>
			///
			/// <param name="xCamera"> [in,out]The camera instance. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CCamera(CCamera&& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Destructor.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			~CCamera();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Adds the given callback function with the given context to the list of image captured callbacks.
			///
			/// 	If the given callback function is already in the list, only the context is updated to the given one.
			/// </summary>
			///
			/// <param name="pxCallback"> The callback function. Must not be null. </param>
			/// <param name="pvContext">  [in] The context pointer. Can be null. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void AddImageCapturedCallback(TFuncImageCaptured pxCallback, void* pvContext);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Removes the given callback function from the list of image captured callbacks. Does nothing if it's not in the list.
			/// </summary>
			///
			/// <param name="pxCallback"> The callback function to remove. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void RemoveImageCapturedCallback(TFuncImageCaptured pxCallback);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the format of the images captured by this camera.
			/// </summary>
			///
			/// <returns> The image format. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			const CRxImageFormat& GetImageFormat() const;

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Query if this camera is open.
			/// </summary>
			///
			/// <returns> True if open, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool IsOpen() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the driver name, e.g. "TypeA".
			/// </summary>
			///
			/// <returns> The driver name. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			const CRxString& GetDriverName() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the internal serial string. Is only available after the camera has been initialized.
			/// </summary>
			///
			/// <returns> The internal serial. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			const CRxString& GetInternalSerial() const;

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the camera index. This is the index in the list of cameras in the camera server.
			/// </summary>
			///
			/// <returns> The index. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			unsigned GetIndex() const;

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Opens the device and prepares the communication.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Open();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Closes the device and finalizes the communication. Does nothing if not open.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Close();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Starts the camera. The configured trigger mode determines when the camera captures images.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Start();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Starts the camera. The given trigger mode determines when the camera captures images.
			/// </summary>
			///
			/// <param name="eTriggerMode"> The trigger mode. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Start(Interop::Runtime30::Camera::ETriggerMode::ID eTriggerMode);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Stops the camera.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Stop();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Suspends the camera.
			/// </summary>
			///
			/// <param name="bSuspend"> True to suspend, false to unsuspend. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Suspend(bool bSuspend);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Triggers the camera.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void Trigger();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Queries if a property is available.
			/// </summary>
			///
			/// <param name="eProp"> [in] The property in question. </param>
			///
			/// <returns> True if the property is available, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			bool IsPropertyAvailable(Interop::Runtime30::Camera::EProperty::ID eProp);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets a property value of type float.
			/// </summary>
			///
			/// <param name="eProp">  [in] The property in question. </param>
			/// <param name="fValue"> [out] The return value. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void GetProperty(Interop::Runtime30::Camera::EProperty::ID eProp, float& fValue);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets a property value of type int.
			/// </summary>
			///
			/// <param name="eProp">  [in] The property in question. </param>
			/// <param name="iValue"> [out] The return value. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void GetProperty(Interop::Runtime30::Camera::EProperty::ID eProp, int& iValue);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the value of a string property.
			/// </summary>
			///
			/// <param name="eProp">   The property. </param>
			/// <param name="sxValue"> [out] The string value. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void GetProperty(Interop::Runtime30::Camera::EProperty::ID eProp, CRxString& sxValue) const;

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets a property value of type float.
			/// </summary>
			///
			/// <param name="eProp">  [in] The property to be changed. </param>
			/// <param name="fValue"> [in] The value to be set. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void SetProperty(Interop::Runtime30::Camera::EProperty::ID eProp, float fValue);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets a property value of type int.
			/// </summary>
			///
			/// <param name="eProp">  [in] The property to be changed. </param>
			/// <param name="iValue"> [in] The value to be set. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void SetProperty(Interop::Runtime30::Camera::EProperty::ID eProp, int iValue);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the value of a string property.
			/// </summary>
			///
			/// <param name="eProp">   The property. </param>
			/// <param name="sxValue"> The string value. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void SetProperty(Interop::Runtime30::Camera::EProperty::ID eProp, const CRxString& sxValue);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the property value range of the given property of type float.
			/// </summary>
			///
			/// <param name="eProp"> [in] The property in question. </param>
			/// <param name="fMin">  [out] The minimum value for given property. </param>
			/// <param name="fMax">  [out] The maximum value for given property. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void GetPropertyRange(Interop::Runtime30::Camera::EProperty::ID eProp, float& fMin, float& fMax);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the property value range of the given property of type int.
			/// </summary>
			///
			/// <param name="eProp"> [in] The property in question. </param>
			/// <param name="iMin">  [out] The minimum value for given property. </param>
			/// <param name="iMax">  [out] The maximum value for given property. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void GetPropertyRange(Interop::Runtime30::Camera::EProperty::ID eProp, int& iMin, int& iMax);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the possible values of an integer property.
			/// </summary>
			///
			/// <param name="eProp">   The property. </param>
			/// <param name="aiValue"> [out] The values. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void GetPropertyRange(Interop::Runtime30::Camera::EProperty::ID eProp, CRxArrayInt& aiValue);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the camera interface.
			/// </summary>
			///
			/// <param name="eData"> The interface type. </param>
			///
			/// <returns> Null if it fails, else the interface. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			void* GetInterface(Interfaces::ECamera::ID eData);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the camera interface.
			/// </summary>
			///
			/// <param name="eData"> The interface type. </param>
			///
			/// <returns> Null if it fails, else the interface. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			const void* GetInterface(Interfaces::ECamera::ID eData) const;

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Move assignment operator.
			/// </summary>
			///
			/// <param name="xCamera"> [in,out]The camera instance. </param>
			///
			/// <returns> The instance. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CCamera& operator=(CCamera&& xCamera);
		};
	}
}
