/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "DLLInterface.h"
#include "Pimpl.h"

#include "Rx.Core.Dongle/RxDongle.Features.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 	A macro that ensures the support of a certain feature.
/// </summary>
///
/// <param name="theFeature"> The feature. </param>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define RX_ENSURE_FEATURE(theFeature) \
	if (!LFR::CLightFieldRuntime::IsAuthenticated()) \
	{ \
		RX_THROW(CRxException, RX_S "The Light Field Runtime has not been authenticated"); \
	} \
	if (!LFR::CLightFieldRuntime::IsFeatureSupported(theFeature)) \
	{ \
		RX_THROW(CRxException, RX_S "The feature '" << #theFeature << "' is not supported by your license"); \
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx.LFR
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class CLightFieldRuntime_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Provides methods for authenticating with the Light Field Runtime and for querying LFR parameters.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API CLightFieldRuntime : public CPimpl<CLightFieldRuntime_Impl, Interfaces::ELightFieldRuntime::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Authenticates the attached USB dongle with the Light Field Runtime.
			///
			/// 	An exception is thrown in the following cases:
			///
			/// 	* There is no USB dongle attached to the system.
			/// 	* This version of the Light Field Runtime is not supported by the dongle license.
			/// 	* The dongle license does not include the SDK feature.
			/// </summary>
			///
			/// <param name="pvData"> [in] (Optional) Pointer to internal data. The passed pointer is stored in this class and must be
			/// 					  available for the lifetime of this class and is deleted by calling End. Should be null. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Authenticate(void* pvData = nullptr);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Queries if a USB dongle is authenticated with the Light Field Runtime.
			/// </summary>
			///
			/// <returns> True if authenticated, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool IsAuthenticated();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the release date of this Light Field Runtime. Does not need to be authenticated to get the release date.
			/// </summary>
			///
			/// <param name="iDay">   [out] The release day. </param>
			/// <param name="iMonth"> [out] The release month. </param>
			/// <param name="iYear">  [out] The release year. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetReleaseDate(int& iDay, int& iMonth, int& iYear);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets application details.
			/// </summary>
			///
			/// <param name="sxAppName">    Name of the sx application. </param>
			/// <param name="sxAppVersion"> The application version. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SetApplicationDetails(const CRxString& sxAppName, const CRxString& sxAppVersion);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets application details.
			/// </summary>
			///
			/// <param name="sxAppName">    [in,out] Name of the application. </param>
			/// <param name="sxAppVersion"> [in,out] The application version. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetApplicationDetails(CRxString& sxAppName, CRxString& sxAppVersion);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Finalizes the Light Field Runtime. Frees the memory used by this class. Finalizes also the Cuda device but does not
			/// 	finalize other classes.
			///
			/// 	This function is NOT called automatically. You have to call this method at the end of you application.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void End();

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Queries if the given feature is supported by your dongle. Returns always false if called before Authenticate.
			/// </summary>
			///
			/// <param name="eFeatureID"> The feature ID to query. </param>
			///
			/// <returns> True if the feature is supported, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool IsFeatureSupported(Dongle::ERuntimeFeature::ID eFeatureID);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Queries if the given features are supported by your dongle. Returns always false if called before Authenticate.
			/// </summary>
			///
			/// <param name="uFeatureIDs"> A OR-ed list of Dongle::ERuntimeFeature::ID to query. </param>
			///
			/// <returns> True if all features are supported, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool IsFeatureSupported(unsigned uFeatureIDs);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Get the IDs of the attached dongle.
			/// </summary>
			///
			/// <param name="iDongleID">  [Out] The hardware dongle ID. </param>
			/// <param name="iRaytrixID"> [Out] The Raytrix dongle ID. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetDongleIDs(int& iDongleID, int& iRaytrixID);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Decodes both given input keys into the given output keys using the USB dongle.
			/// </summary>
			///
			/// <param name="uOutKey1"> [out] The first output key. </param>
			/// <param name="uOutKey2"> [out] The second output key. </param>
			/// <param name="uInKey1">  The first input key. </param>
			/// <param name="uInKey2">  The second input key. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Decode(unsigned& uOutKey1, unsigned& uOutKey2, unsigned uInKey1, unsigned uInKey2);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the interface defined by ELightFieldRuntimeInterface.
			/// </summary>
			///
			/// <param name="eData"> The interface type. </param>
			///
			/// <returns> Null if it fails, else the interface. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void* GetInterface(Interfaces::ELightFieldRuntime::ID eData);

		private:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			CLightFieldRuntime();
			~CLightFieldRuntime();
			CLightFieldRuntime(const CLightFieldRuntime&);
			CLightFieldRuntime& operator=(const CLightFieldRuntime&);
		};
	}
}
