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

#include <stdexcept>
#include <stdlib.h> /* getenv */

#define LOAD_LIBSYM(symName)  p##symName = reinterpret_cast<GenTL::P##symName>(findSymbol(#symName));

namespace genSDK
{

GTL_Producer::GTL_Producer(std::string producer)
{
	openLibrary(producer.c_str());
}
GTL_Producer::~GTL_Producer()
{
	closeLibrary();
}

void* GTL_Producer::findSymbol(const std::string name)
{
#ifdef _WIN32 // Windows
    void* pSymbol = static_cast<void*>(GetProcAddress(libHandle, name.c_str()));
#elif defined( __GNUC__ )
    void* pSymbol = static_cast<void*>(dlsym(libHandle, name.c_str()));
#else
#   error Unknown compiler!
#endif
    return pSymbol;
}

void GTL_Producer::openLibrary(const char* producer)
{
#ifdef _WIN32 // Windows
    libHandle = LoadLibrary(producer);
#elif defined( __GNUC__ )
    libHandle = dlopen(producer, RTLD_LAZY);
#else
#   error Unknown compiler!
#endif
    if (libHandle == nullptr) {
        throw std::runtime_error("Failed to open genTL producer!");
    }

    LOAD_LIBSYM(GCGetInfo);
    LOAD_LIBSYM(GCGetLastError);
    LOAD_LIBSYM(GCInitLib);
	LOAD_LIBSYM(GCCloseLib);
	LOAD_LIBSYM(GCReadPort);
	LOAD_LIBSYM(GCWritePort);
	LOAD_LIBSYM(GCGetPortURL);
	LOAD_LIBSYM(GCGetPortInfo);

	LOAD_LIBSYM(GCRegisterEvent);
	LOAD_LIBSYM(GCUnregisterEvent);
	LOAD_LIBSYM(EventGetData);
	LOAD_LIBSYM(EventGetDataInfo);
	LOAD_LIBSYM(EventGetInfo);
	LOAD_LIBSYM(EventFlush);
	LOAD_LIBSYM(EventKill);
	LOAD_LIBSYM(TLOpen);
	LOAD_LIBSYM(TLClose);
	LOAD_LIBSYM(TLGetInfo);
	LOAD_LIBSYM(TLGetNumInterfaces);
	LOAD_LIBSYM(TLGetInterfaceID);
	LOAD_LIBSYM(TLGetInterfaceInfo);
	LOAD_LIBSYM(TLOpenInterface);
	LOAD_LIBSYM(TLUpdateInterfaceList);
	LOAD_LIBSYM(IFClose);
	LOAD_LIBSYM(IFGetInfo);
	LOAD_LIBSYM(IFGetNumDevices);
	LOAD_LIBSYM(IFGetDeviceID);
	LOAD_LIBSYM(IFUpdateDeviceList);
	LOAD_LIBSYM(IFGetDeviceInfo);
	LOAD_LIBSYM(IFOpenDevice);

	LOAD_LIBSYM(DevGetPort);
	LOAD_LIBSYM(DevGetNumDataStreams);
	LOAD_LIBSYM(DevGetDataStreamID);
	LOAD_LIBSYM(DevOpenDataStream);
	LOAD_LIBSYM(DevGetInfo);
	LOAD_LIBSYM(DevClose);

	LOAD_LIBSYM(DSAnnounceBuffer);
	LOAD_LIBSYM(DSAllocAndAnnounceBuffer);
	LOAD_LIBSYM(DSFlushQueue);
	LOAD_LIBSYM(DSStartAcquisition);
	LOAD_LIBSYM(DSStopAcquisition);
	LOAD_LIBSYM(DSGetInfo);
	LOAD_LIBSYM(DSGetBufferID);
	LOAD_LIBSYM(DSClose);
	LOAD_LIBSYM(DSRevokeBuffer);
	LOAD_LIBSYM(DSQueueBuffer);
	LOAD_LIBSYM(DSGetBufferInfo);

	/* GenTLv1.1 */
	LOAD_LIBSYM(GCGetNumPortURLs);
	LOAD_LIBSYM(GCGetPortURLInfo);
	LOAD_LIBSYM(GCReadPortStacked);
	LOAD_LIBSYM(GCWritePortStacked);

	/* GenTLv1.3 */
	LOAD_LIBSYM(DSGetBufferChunkData);

	/* GenTLv1.4 */
	LOAD_LIBSYM(IFGetParentTL);
	LOAD_LIBSYM(DevGetParentIF);
	LOAD_LIBSYM(DSGetParentDev);

	/* GenTLv1.5 */
	LOAD_LIBSYM(DSGetNumBufferParts);
	LOAD_LIBSYM(DSGetBufferPartInfo);
}

void GTL_Producer::closeLibrary()
{
#ifdef _WIN32 // Windows
  FreeLibrary(libHandle);
#elif defined( __GNUC__ )
  dlclose(libHandle);
#else
#   error Unknown compiler!
#endif
}
 
} /* namespace */
