/**
 * \file    GTL_Producer.hpp
 * \author  Silvan Murer
 * \date    28 Jul 2022
 *
 * \brief   C++ class for wrapping and dynamic load of GenTL v1.5 producer
 */

#ifndef INC_GENTLDL
#define INC_GENTLDL

#include "GenTL.h"
 
#ifdef _WIN32 // Windows
#include <Windows.h>
#else // Linux
#include <dlfcn.h>
#endif

#include <functional>
#include <string>

namespace genSDK
{
 
 #ifdef _WIN32 // Windows
typedef HMODULE GTL_libHdl_t;
#else // Linux
typedef void* GTL_libHdl_t;
#endif
 
class GTL_Producer {
private:
	GTL_libHdl_t libHandle;

	/**
	 * \brief		open function/symbol from the shared library handle
	 *
	 * \param[in]   name  name of the function/symbol
	 *
	 * \return      pointer to the function/symbol
	 */
	void* findSymbol(const std::string name);
	/**
	 * \brief	     open and dynamic load of genTL producer library
	 *
	 * \param[in]    producer   file (and path) of the genTL producer library (null-terminated)
	 */
	void openLibrary(const char* producer);
	/**
	 * \brief	     close the shared library and clean internal function pointers
	 */
	void closeLibrary();

public:
	GTL_Producer(std::string producer);
	~GTL_Producer();

	/* define function pointers to GenTL functions */
	std::function<decltype(GenTL::GCGetInfo)> pGCGetInfo;
	std::function<decltype(GenTL::GCGetLastError)> pGCGetLastError;
	std::function<decltype(GenTL::GCInitLib)> pGCInitLib;
	std::function<decltype(GenTL::GCCloseLib)> pGCCloseLib;
	std::function<decltype(GenTL::GCReadPort)> pGCReadPort;
	std::function<decltype(GenTL::GCWritePort)> pGCWritePort;
	std::function<decltype(GenTL::GCGetPortURL)> pGCGetPortURL;
	std::function<decltype(GenTL::GCGetPortInfo)> pGCGetPortInfo;

	std::function<decltype(GenTL::GCRegisterEvent)> pGCRegisterEvent;
	std::function<decltype(GenTL::GCUnregisterEvent)> pGCUnregisterEvent;
	std::function<decltype(GenTL::EventGetData)> pEventGetData;
	std::function<decltype(GenTL::EventGetDataInfo)> pEventGetDataInfo;
	std::function<decltype(GenTL::EventGetInfo)> pEventGetInfo;
	std::function<decltype(GenTL::EventFlush)> pEventFlush;
	std::function<decltype(GenTL::EventKill)> pEventKill;
	std::function<decltype(GenTL::TLOpen)> pTLOpen;
	std::function<decltype(GenTL::TLClose)> pTLClose;
	std::function<decltype(GenTL::TLGetInfo)> pTLGetInfo;
	std::function<decltype(GenTL::TLGetNumInterfaces)> pTLGetNumInterfaces;
	std::function<decltype(GenTL::TLGetInterfaceID)> pTLGetInterfaceID;
	std::function<decltype(GenTL::TLGetInterfaceInfo)> pTLGetInterfaceInfo;
	std::function<decltype(GenTL::TLOpenInterface)> pTLOpenInterface;
	std::function<decltype(GenTL::TLUpdateInterfaceList)> pTLUpdateInterfaceList;
	std::function<decltype(GenTL::IFClose)> pIFClose;
	std::function<decltype(GenTL::IFGetInfo)> pIFGetInfo;
	std::function<decltype(GenTL::IFGetNumDevices)> pIFGetNumDevices;
	std::function<decltype(GenTL::IFGetDeviceID)> pIFGetDeviceID;
	std::function<decltype(GenTL::IFUpdateDeviceList)> pIFUpdateDeviceList;
	std::function<decltype(GenTL::IFGetDeviceInfo)> pIFGetDeviceInfo;
	std::function<decltype(GenTL::IFOpenDevice)> pIFOpenDevice;

	std::function<decltype(GenTL::DevGetPort)> pDevGetPort;
	std::function<decltype(GenTL::DevGetNumDataStreams)> pDevGetNumDataStreams;
	std::function<decltype(GenTL::DevGetDataStreamID)> pDevGetDataStreamID;
	std::function<decltype(GenTL::DevOpenDataStream)> pDevOpenDataStream;
	std::function<decltype(GenTL::DevGetInfo)> pDevGetInfo;
	std::function<decltype(GenTL::DevClose)> pDevClose;

	std::function<decltype(GenTL::DSAnnounceBuffer)> pDSAnnounceBuffer;
	std::function<decltype(GenTL::DSAllocAndAnnounceBuffer)> pDSAllocAndAnnounceBuffer;
	std::function<decltype(GenTL::DSFlushQueue)> pDSFlushQueue;
	std::function<decltype(GenTL::DSStartAcquisition)> pDSStartAcquisition;
	std::function<decltype(GenTL::DSStopAcquisition)> pDSStopAcquisition;
	std::function<decltype(GenTL::DSGetInfo)> pDSGetInfo;
	std::function<decltype(GenTL::DSGetBufferID)> pDSGetBufferID;
	std::function<decltype(GenTL::DSClose)> pDSClose;
	std::function<decltype(GenTL::DSRevokeBuffer)> pDSRevokeBuffer;
	std::function<decltype(GenTL::DSQueueBuffer)> pDSQueueBuffer;
	std::function<decltype(GenTL::DSGetBufferInfo)> pDSGetBufferInfo;

	/* GenTLv1.1 */
	std::function<decltype(GenTL::GCGetNumPortURLs)> pGCGetNumPortURLs;
	std::function<decltype(GenTL::GCGetPortURLInfo)> pGCGetPortURLInfo;
	std::function<decltype(GenTL::GCReadPortStacked)> pGCReadPortStacked;
	std::function<decltype(GenTL::GCWritePortStacked)> pGCWritePortStacked;

	/* GenTLv1.3 */
	std::function<decltype(GenTL::DSGetBufferChunkData)> pDSGetBufferChunkData;

	/* GenTLv1.4 */
	std::function<decltype(GenTL::IFGetParentTL)> pIFGetParentTL;
	std::function<decltype(GenTL::DevGetParentIF)> pDevGetParentIF;
	std::function<decltype(GenTL::DSGetParentDev)> pDSGetParentDev;

	/* GenTLv1.5 */
	std::function<decltype(GenTL::DSGetNumBufferParts)> pDSGetNumBufferParts;
	std::function<decltype(GenTL::DSGetBufferPartInfo)> pDSGetBufferPartInfo;

};
 
} /* namespace */

#endif
