/**
 * \file    M_Xml.cpp
 * \author  Silvan Murer
 * \date    01 Aug 2022
 *
 * \brief   Internal class helps for get access to the XML content of a GenTL component (interface, device, ...)
 */

#include "M_Xml.hpp"

#include <cstring>

using namespace GenTL;
using namespace genSDK;

namespace mimic {

uint32_t M_Xml::getNofXMLs(std::shared_ptr<GTL_Producer> gtl_producer, PORT_HANDLE hPort)
{
	try {
		uint32_t nofURLs = 0;
		GC_ERROR err = gtl_producer->pGCGetNumPortURLs(hPort, &nofURLs);
		if (err != GenTL::GC_ERROR_LIST::GC_ERR_SUCCESS) {
			throw Mimic_GenTL_Exception("GenTL error", err);
		}
		return nofURLs;
	}
	catch (const std::bad_function_call& e) {
		std::string exMsg = std::string("GenTL Producer function not initialized (GCGetNumPortURLs)! ") + e.what();
		throw Mimic_GenTL_Exception(exMsg, -500);
	}
	catch (...) {
		throw; // throw the exception to the user
	}
}

void M_Xml::getXMLInfo(std::shared_ptr<GTL_Producer> gtl_producer, GenTL::PORT_HANDLE hPort, uint32_t urlIdx, std::string& xmlName, uint64_t& xmlAddress, uint64_t& xmlSize)
{
	try {
		uint32_t numURLs = getNofXMLs(gtl_producer, hPort);
		if ((numURLs - 1) < (urlIdx))
		{
			throw Mimic_OutOfRange_Exception("The given urlIdx is outof range!", -100);
		}

		GC_ERROR err;
		GenTL::INFO_DATATYPE dataType;
		size_t bufSize = 0;
		std::vector<char> buf;

		// read XML name
		gtl_producer->pGCGetPortURLInfo(hPort, urlIdx, URL_INFO_FILENAME, &dataType, nullptr, &bufSize);
		buf.resize(bufSize, 0);
		bufSize = buf.size();
		err = gtl_producer->pGCGetPortURLInfo(hPort, urlIdx, URL_INFO_FILENAME, &dataType, buf.data(), &bufSize);
		if (err != GenTL::GC_ERROR_LIST::GC_ERR_SUCCESS) {
			throw Mimic_GenTL_Exception("GenTL error", err);
		}
		xmlName = std::string(buf.data(), buf.size());

		// read XML address
		bufSize = 0;
		gtl_producer->pGCGetPortURLInfo(hPort, urlIdx, URL_INFO_FILE_REGISTER_ADDRESS, &dataType, nullptr, &bufSize);
		buf.resize(bufSize, 0);
		bufSize = buf.size();
		err = gtl_producer->pGCGetPortURLInfo(hPort, urlIdx, URL_INFO_FILE_REGISTER_ADDRESS, &dataType, buf.data(), &bufSize);
		if ((err != GC_ERROR_LIST::GC_ERR_SUCCESS) || (dataType != INFO_DATATYPE_LIST::INFO_DATATYPE_UINT64)) {
			throw Mimic_GenTL_Exception("GenTL error", err);
		}
		std::memcpy(&xmlAddress, buf.data(), sizeof(xmlAddress));

		bufSize = 0;
		gtl_producer->pGCGetPortURLInfo(hPort, urlIdx, URL_INFO_FILE_SIZE, &dataType, nullptr, &bufSize);
		buf.resize(bufSize, 0);
		bufSize = buf.size();
		err = gtl_producer->pGCGetPortURLInfo(hPort, urlIdx, URL_INFO_FILE_SIZE, &dataType, buf.data(), &bufSize);
		if ((err != GC_ERROR_LIST::GC_ERR_SUCCESS) || (dataType != INFO_DATATYPE_LIST::INFO_DATATYPE_UINT64)) {
			throw Mimic_GenTL_Exception("GenTL error", err);
		}
		std::memcpy(&xmlSize, buf.data(), sizeof(xmlAddress));
	}
	catch (const std::bad_function_call& e) {
		std::string exMsg = std::string("GenTL Producer function not initialized (pGCGetPortURLInfo)! ") + e.what();
		throw Mimic_GenTL_Exception(exMsg, -500);
	}
	catch (...) {
		throw; // throw the exception to the user
	}
}
std::string M_Xml::getXMLContent(std::shared_ptr<GTL_Producer> gtl_producer, GenTL::PORT_HANDLE hPort, uint64_t xmlAddress, uint64_t xmlSize)
{
	try {
		std::string xmlFile;
		xmlFile.resize(xmlSize, '\0');
		size_t readPortSize = xmlSize;
		GC_ERROR err = gtl_producer->pGCReadPort(hPort, xmlAddress, &xmlFile.front(), &readPortSize);
		if (err != GC_ERROR_LIST::GC_ERR_SUCCESS) {
			throw Mimic_GenTL_Exception("GenTL error", err);
		}
		return xmlFile;
	}
	catch (const std::bad_function_call& e) {
		std::string exMsg = std::string("GenTL Producer function not initialized (pGCReadPort)! ") + e.what();
		throw Mimic_GenTL_Exception(exMsg, -500);
	}
	catch (...) {
		throw; // throw the exception to the user
	}
}


} /* namespace genSDK */
