/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "DLLInterface.h"

#include "Pimpl.h"

#include "Camera.h"
#include "Calibration.h"

#include "Rx.Core/RxString.h"
#include "Rx.Core/RxCalibMetaData.h"
#include "Rx.Core.Ex/RxArrayString.h"

#include <utility>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx.LFR
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	namespace LFR
	{
		class CCalibrationManager_Impl;

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Provides methods for managing camera calibrations. This includes creating, loading and saving.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		class RX_API CCalibrationManager : public CPimpl<CCalibrationManager_Impl, Interfaces::ECalibManager::ID>
		{
		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Initializes this calibration manager and reads all calibrations from disk.
			///
			/// 	You don't need to call this method. It's called automatically on the first access. But you can call it if you want to
			/// 	change the calibration folder or if you want to initialize this class at a certain time.
			/// </summary>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Initialize();

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Initializes this calibration manager and reads all calibrations from disk.
			///
			/// 	You don't need to call this method. It's called automatically on the first access. But you can call it if you want to
			/// 	change the calibration folder or if you want to initialize this class at a certain time.
			/// </summary>
			///
			/// <param name="sxFolder"> The folder that holds the calibrations. If empty, the default folder is used. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Initialize(const CRxString& sxFolder);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Queries if the there is a calibration database for the given camera.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			///
			/// <returns> True if a database for the given camera exists, false if not. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool HasDatabase(const CCamera& xCamera);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates a calibration database for the given camera.
			///
			/// 	Requires Dongle::ERuntimeFeature::Master.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			/// <param name="bForce">  True to enforce the creation even if the calibration already exists. Otherwise an exception is
			/// 					   thrown. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void CreateDatabase(const CCamera& xCamera, bool bForce);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates a calibration database for the given camera (defined by type and serial).
			///
			/// 	Requires Dongle::ERuntimeFeature::Master.
			/// </summary>
			///
			/// <param name="sxCamType">   The camera type. This is 'TypeA' for type A cameras. </param>
			/// <param name="sxCamSerial"> The camera serial. </param>
			/// <param name="bForce">	   True to enforce the creation even if the calibration already exists. Otherwise an exception is
			/// 						   thrown. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void CreateDatabase(const CRxString& sxCamType, const CRxString& sxCamSerial, bool bForce);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates a calibration database for the given camera (defined by hardware ID).
			///
			/// 	Requires Dongle::ERuntimeFeature::Master.
			/// </summary>
			///
			/// <param name="sxCamHardwareID"> The camera hardware ID. This is 'TypeA_012' for type A cameras with serial 012. </param>
			/// <param name="bForce">		   True to enforce the creation even if the calibration already exists. Otherwise an exception
			/// 							   is thrown. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void CreateDatabase(const CRxString& sxCamHardwareID, bool bForce);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates a new calibration and assigns it to the given camera.
			///
			/// 	Requires Dongle::ERuntimeFeature::Save to save this change permanently.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			///
			/// <returns> The GUID of the created calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString CreateCalibration(const CCamera& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates a new calibration and assigns it to the given camera (defined by type and serial).
			///
			/// 	Requires Dongle::ERuntimeFeature::Save to save this change permanently.
			/// </summary>
			///
			/// <param name="sxCamType">   The camera type. This is 'TypeA' for type A cameras. </param>
			/// <param name="sxCamSerial"> The camera serial. </param>
			///
			/// <returns> The GUID of the created calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString CreateCalibration(const CRxString& sxCamType, const CRxString& sxCamSerial);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Creates a new calibration and assigns it to the given camera (defined by hardware ID).
			///
			/// 	Requires Dongle::ERuntimeFeature::Save to save this change permanently.
			/// </summary>
			///
			/// <param name="sxCamHardwareID"> The camera hardware ID. This is 'TypeA_012' for type A cameras with serial 012. </param>
			///
			/// <returns> The GUID of the created calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString CreateCalibration(const CRxString& sxCamHardwareID);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Deletes the calibration with the given GUID.
			///
			/// 	Requires Dongle::ERuntimeFeature::Save to save this change permanently.
			/// </summary>
			///
			/// <param name="sxGUID"> The GUID of the calibration. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void DeleteCalibration(const CRxString& sxGUID);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Loads the calibration with the given GUID.
			/// </summary>
			///
			/// <param name="xCalib">	    [out] The loaded calibration. </param>
			/// <param name="sxGUID">	    The GUID of the calibration. </param>
			/// <param name="bLoadGrayImg"> True to load the gray image from disk. The image is invalid if there isn't a gray image. False
			/// 							to keep the gray image of the given calibration. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void LoadCalibration(CCalibration& xCalib, const CRxString& sxGUID, bool bLoadGrayImg);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Loads the default calibration of the given camera.
			///
			/// 	The default calibration is a calibration that has been set as default by calling SetMetaData with a CRxCalibMetaData
			/// 	that has the IsDefaultCalib flag set to true. By default an internal master calibration is the default one.
			/// </summary>
			///
			/// <param name="xCalib">	    [out] The loaded calibration. </param>
			/// <param name="xCamera">	    The camera. </param>
			/// <param name="bLoadGrayImg"> True to load the gray image from disk. The image is invalid if there isn't a gray image. False
			/// 							to keep the gray image of the given calibration. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void LoadDefaultCalibration(CCalibration& xCalib, const CCamera& xCamera, bool bLoadGrayImg);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Loads the default calibration of the given camera defined by the camera serial and the driver name.
			///
			/// 	The default calibration is a calibration that has been set as default by calling SetMetaData with a CRxCalibMetaData
			/// 	that has the IsDefaultCalib flag set to true. By default an internal master calibration is the default one.
			/// </summary>
			///
			/// <param name="xCalib">		 [out] The loaded calibration. </param>
			/// <param name="sCameraSerial"> The camera serial. </param>
			/// <param name="sDriverName">   The driver name. </param>
			/// <param name="bLoadGrayImg">  True to load the gray image from disk. The image is invalid if there isn't a gray image. False
			/// 							 to keep the gray image of the given calibration. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void LoadDefaultCalibration(CCalibration& xCalib, const CRxString& sCameraSerial, const CRxString& sDriverName, bool bLoadGrayImg);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Saves the given calibration to disk.
			///
			/// 	Requires Dongle::ERuntimeFeature::Save to save this change permanently.
			/// </summary>
			///
			/// <param name="xCalib">	    The calibration. </param>
			/// <param name="sxGUID">	    The GUID of the calibration. </param>
			/// <param name="bSaveGrayImg"> True to save the gray image to disk. Throws an exception if the gray image is invalid. False to
			/// 							keep the current gray image. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SaveCalibration(const CCalibration& xCalib, const CRxString& sxGUID, bool bSaveGrayImg);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets an array of GUIDs from all calibrations.
			/// </summary>
			///
			/// <param name="asxGUIDs"> [out] The GUIDs array. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetCalibrationGUIDs(CRxArrayString& asxGUIDs);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets an array of GUIDs from all calibrations of the given camera.
			/// </summary>
			///
			/// <param name="asxGUIDs"> [out] The GUIDs array. </param>
			/// <param name="xCamera">  The camera. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetCalibrationGUIDs(CRxArrayString& asxGUIDs, const CCamera& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets an array of GUIDs from all master calibrations. Each camera has a single master calibration.
			/// </summary>
			///
			/// <param name="asxGUIDs"> [out] The GUIDs array. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetMasterCalibrationGUIDs(CRxArrayString& asxGUIDs);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the GUID of the master calibration of the given camera.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			///
			/// <returns> The GUID of the master calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString GetMasterCalibrationGUID(const CCamera& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the GUID of the master calibration of the given camera defined by the camera serial and the driver name.
			/// </summary>
			///
			/// <param name="sxSerial"> [in] The serial of the camera. </param>
			/// <param name="sxDriver"> [in] The driver name of the camera. </param>
			///
			/// <returns> The GUID of the master calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString GetMasterCalibrationGUID(const CRxString& sxSerial, const CRxString& sxDriver);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the GUID of the default calibration of the given camera.
			///
			/// 	The default calibration is a calibration that has been set as default by calling SetMetaData with a CRxCalibMetaData
			/// 	that has the IsDefaultCalib flag set to true. By default an internal master calibration is the default one.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			///
			/// <returns> The GUID of the default calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString GetDefaultCalibrationGUID(const CCamera& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the GUID of the default calibration of the given camera defined by the camera serial and the driver name.
			///
			/// 	The default calibration is a calibration that has been set as default by calling SetMetaData with a CRxCalibMetaData
			/// 	that has the IsDefaultCalib flag set to true. By default an internal master calibration is the default one.
			/// </summary>
			///
			/// <param name="sxSerial"> The serial of the camera. </param>
			/// <param name="sxDriver"> The driver name of the camera. </param>
			///
			/// <returns> The GUID of the default calibration. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString GetDefaultCalibrationGUID(const CRxString& sxSerial, const CRxString& sxDriver);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the calibration meta data of the given calibration.
			/// </summary>
			///
			/// <param name="xData">  [out] The meta data. </param>
			/// <param name="sxGUID"> The GUID of the calibration. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void GetMetaData(CRxCalibMetaData& xData, const CRxString& sxGUID);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the calibration meta data of the given calibration. The meta data of the master calibration cannot be set.
			///
			/// 	Requires Dongle::ERuntimeFeature::Save to save this change permanently.
			/// </summary>
			///
			/// <param name="xData">  The meta data. </param>
			/// <param name="sxGUID"> The GUID of the calibration. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SetMetaData(const CRxCalibMetaData& xData, const CRxString& sxGUID);

		public:

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the Raytrix name of the given camera. Requires Dongle::ERuntimeFeature::Master.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			/// <param name="sxName">  The name. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SetCameraName(const CCamera& xCamera, const CRxString& sxName);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Sets the Raytrix serial of the given camera. Requires Dongle::ERuntimeFeature::Master.
			/// </summary>
			///
			/// <param name="xCamera">  The camera. </param>
			/// <param name="sxSerial"> The name. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SetCameraSerial(const CCamera& xCamera, const CRxString& sxSerial);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the Raytrix name of the given camera.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			///
			/// <returns> The Raytrix camera name. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString GetCameraName(const CCamera& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the Raytrix serial of the given camera.
			/// </summary>
			///
			/// <param name="xCamera"> The camera. </param>
			///
			/// <returns> The Raytrix camera serial. </returns>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static CRxString GetCameraSerial(const CCamera& xCamera);

			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 	Gets the interface defined by ECalibrationManagerInterface.
			/// </summary>
			///
			/// <param name="eData"> The interface type. </param>
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			static void* GetInterface(Interfaces::ECalibManager::ID eData);

		private:

			CCalibrationManager();
			CCalibrationManager(const CCalibrationManager&);
			~CCalibrationManager();
			CCalibrationManager& operator=(const CCalibrationManager&);
		};
	}
}
