<reponame>GibbekAdsk/AutodeskMachineControlFramework<filename>Drivers/S7Net/Interfaces/libmcdriver_s7net_interfacewrapper.cpp
/*++

Copyright (C) 2020 Autodesk Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Autodesk Inc. nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


This file has been generated by the Automatic Component Toolkit (ACT) version 1.7.0-develop.

Abstract: This is an autogenerated C++ implementation file in order to allow easy
development of MC Driver S7Net 2.0. The functions in this file need to be implemented. It needs to be generated only once.

Interface version: 1.0.0

*/

#include "libmcdriver_s7net_abi.hpp"
#include "libmcdriver_s7net_interfaces.hpp"
#include "libmcdriver_s7net_interfaceexception.hpp"

#include <map>

using namespace LibMCDriver_S7Net::Impl;

LibMCDriver_S7NetResult handleLibMCDriver_S7NetException(IBase * pIBaseClass, ELibMCDriver_S7NetInterfaceException & Exception)
{
	LibMCDriver_S7NetResult errorCode = Exception.getErrorCode();

	if (pIBaseClass != nullptr)
		pIBaseClass->RegisterErrorMessage(Exception.what());

	return errorCode;
}

LibMCDriver_S7NetResult handleStdException(IBase * pIBaseClass, std::exception & Exception)
{
	LibMCDriver_S7NetResult errorCode = LIBMCDRIVER_S7NET_ERROR_GENERICEXCEPTION;

	if (pIBaseClass != nullptr)
		pIBaseClass->RegisterErrorMessage(Exception.what());

	return errorCode;
}

LibMCDriver_S7NetResult handleUnhandledException(IBase * pIBaseClass)
{
	LibMCDriver_S7NetResult errorCode = LIBMCDRIVER_S7NET_ERROR_GENERICEXCEPTION;

	if (pIBaseClass != nullptr)
		pIBaseClass->RegisterErrorMessage("Unhandled Exception");

	return errorCode;
}



/*************************************************************************************************************************
 Class implementation for Base
**************************************************************************************************************************/

/*************************************************************************************************************************
 Class implementation for Driver
**************************************************************************************************************************/
LibMCDriver_S7NetResult libmcdriver_s7net_driver_configure(LibMCDriver_S7Net_Driver pDriver, const char * pConfigurationString)
{
	IBase* pIBaseClass = (IBase *)pDriver;

	try {
		if (pConfigurationString == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sConfigurationString(pConfigurationString);
		IDriver* pIDriver = dynamic_cast<IDriver*>(pIBaseClass);
		if (!pIDriver)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		pIDriver->Configure(sConfigurationString);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_getname(LibMCDriver_S7Net_Driver pDriver, const LibMCDriver_S7Net_uint32 nNameBufferSize, LibMCDriver_S7Net_uint32* pNameNeededChars, char * pNameBuffer)
{
	IBase* pIBaseClass = (IBase *)pDriver;

	try {
		if ( (!pNameBuffer) && !(pNameNeededChars) )
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sName("");
		IDriver* pIDriver = dynamic_cast<IDriver*>(pIBaseClass);
		if (!pIDriver)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		bool isCacheCall = (pNameBuffer == nullptr);
		if (isCacheCall) {
			sName = pIDriver->GetName();

			pIDriver->_setCache (new ParameterCache_1<std::string> (sName));
		}
		else {
			auto cache = dynamic_cast<ParameterCache_1<std::string>*> (pIDriver->_getCache ());
			if (cache == nullptr)
				throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
			cache->retrieveData (sName);
			pIDriver->_setCache (nullptr);
		}
		
		if (pNameNeededChars)
			*pNameNeededChars = (LibMCDriver_S7Net_uint32) (sName.size()+1);
		if (pNameBuffer) {
			if (sName.size() >= nNameBufferSize)
				throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_BUFFERTOOSMALL);
			for (size_t iName = 0; iName < sName.size(); iName++)
				pNameBuffer[iName] = sName[iName];
			pNameBuffer[sName.size()] = 0;
		}
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_gettype(LibMCDriver_S7Net_Driver pDriver, const LibMCDriver_S7Net_uint32 nTypeBufferSize, LibMCDriver_S7Net_uint32* pTypeNeededChars, char * pTypeBuffer)
{
	IBase* pIBaseClass = (IBase *)pDriver;

	try {
		if ( (!pTypeBuffer) && !(pTypeNeededChars) )
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sType("");
		IDriver* pIDriver = dynamic_cast<IDriver*>(pIBaseClass);
		if (!pIDriver)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		bool isCacheCall = (pTypeBuffer == nullptr);
		if (isCacheCall) {
			sType = pIDriver->GetType();

			pIDriver->_setCache (new ParameterCache_1<std::string> (sType));
		}
		else {
			auto cache = dynamic_cast<ParameterCache_1<std::string>*> (pIDriver->_getCache ());
			if (cache == nullptr)
				throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
			cache->retrieveData (sType);
			pIDriver->_setCache (nullptr);
		}
		
		if (pTypeNeededChars)
			*pTypeNeededChars = (LibMCDriver_S7Net_uint32) (sType.size()+1);
		if (pTypeBuffer) {
			if (sType.size() >= nTypeBufferSize)
				throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_BUFFERTOOSMALL);
			for (size_t iType = 0; iType < sType.size(); iType++)
				pTypeBuffer[iType] = sType[iType];
			pTypeBuffer[sType.size()] = 0;
		}
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_getversion(LibMCDriver_S7Net_Driver pDriver, LibMCDriver_S7Net_uint32 * pMajor, LibMCDriver_S7Net_uint32 * pMinor, LibMCDriver_S7Net_uint32 * pMicro, const LibMCDriver_S7Net_uint32 nBuildBufferSize, LibMCDriver_S7Net_uint32* pBuildNeededChars, char * pBuildBuffer)
{
	IBase* pIBaseClass = (IBase *)pDriver;

	try {
		if (!pMajor)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (!pMinor)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (!pMicro)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if ( (!pBuildBuffer) && !(pBuildNeededChars) )
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sBuild("");
		IDriver* pIDriver = dynamic_cast<IDriver*>(pIBaseClass);
		if (!pIDriver)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		bool isCacheCall = (pBuildBuffer == nullptr);
		if (isCacheCall) {
			pIDriver->GetVersion(*pMajor, *pMinor, *pMicro, sBuild);

			pIDriver->_setCache (new ParameterCache_4<LibMCDriver_S7Net_uint32, LibMCDriver_S7Net_uint32, LibMCDriver_S7Net_uint32, std::string> (*pMajor, *pMinor, *pMicro, sBuild));
		}
		else {
			auto cache = dynamic_cast<ParameterCache_4<LibMCDriver_S7Net_uint32, LibMCDriver_S7Net_uint32, LibMCDriver_S7Net_uint32, std::string>*> (pIDriver->_getCache ());
			if (cache == nullptr)
				throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
			cache->retrieveData (*pMajor, *pMinor, *pMicro, sBuild);
			pIDriver->_setCache (nullptr);
		}
		
		if (pBuildNeededChars)
			*pBuildNeededChars = (LibMCDriver_S7Net_uint32) (sBuild.size()+1);
		if (pBuildBuffer) {
			if (sBuild.size() >= nBuildBufferSize)
				throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_BUFFERTOOSMALL);
			for (size_t iBuild = 0; iBuild < sBuild.size(); iBuild++)
				pBuildBuffer[iBuild] = sBuild[iBuild];
			pBuildBuffer[sBuild.size()] = 0;
		}
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_getheaderinformation(LibMCDriver_S7Net_Driver pDriver, const LibMCDriver_S7Net_uint32 nNameSpaceBufferSize, LibMCDriver_S7Net_uint32* pNameSpaceNeededChars, char * pNameSpaceBuffer, const LibMCDriver_S7Net_uint32 nBaseNameBufferSize, LibMCDriver_S7Net_uint32* pBaseNameNeededChars, char * pBaseNameBuffer)
{
	IBase* pIBaseClass = (IBase *)pDriver;

	try {
		if ( (!pNameSpaceBuffer) && !(pNameSpaceNeededChars) )
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if ( (!pBaseNameBuffer) && !(pBaseNameNeededChars) )
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sNameSpace("");
		std::string sBaseName("");
		IDriver* pIDriver = dynamic_cast<IDriver*>(pIBaseClass);
		if (!pIDriver)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		bool isCacheCall = (pNameSpaceBuffer == nullptr) || (pBaseNameBuffer == nullptr);
		if (isCacheCall) {
			pIDriver->GetHeaderInformation(sNameSpace, sBaseName);

			pIDriver->_setCache (new ParameterCache_2<std::string, std::string> (sNameSpace, sBaseName));
		}
		else {
			auto cache = dynamic_cast<ParameterCache_2<std::string, std::string>*> (pIDriver->_getCache ());
			if (cache == nullptr)
				throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
			cache->retrieveData (sNameSpace, sBaseName);
			pIDriver->_setCache (nullptr);
		}
		
		if (pNameSpaceNeededChars)
			*pNameSpaceNeededChars = (LibMCDriver_S7Net_uint32) (sNameSpace.size()+1);
		if (pNameSpaceBuffer) {
			if (sNameSpace.size() >= nNameSpaceBufferSize)
				throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_BUFFERTOOSMALL);
			for (size_t iNameSpace = 0; iNameSpace < sNameSpace.size(); iNameSpace++)
				pNameSpaceBuffer[iNameSpace] = sNameSpace[iNameSpace];
			pNameSpaceBuffer[sNameSpace.size()] = 0;
		}
		if (pBaseNameNeededChars)
			*pBaseNameNeededChars = (LibMCDriver_S7Net_uint32) (sBaseName.size()+1);
		if (pBaseNameBuffer) {
			if (sBaseName.size() >= nBaseNameBufferSize)
				throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_BUFFERTOOSMALL);
			for (size_t iBaseName = 0; iBaseName < sBaseName.size(); iBaseName++)
				pBaseNameBuffer[iBaseName] = sBaseName[iBaseName];
			pBaseNameBuffer[sBaseName.size()] = 0;
		}
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_queryparameters(LibMCDriver_S7Net_Driver pDriver)
{
	IBase* pIBaseClass = (IBase *)pDriver;

	try {
		IDriver* pIDriver = dynamic_cast<IDriver*>(pIBaseClass);
		if (!pIDriver)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		pIDriver->QueryParameters();

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}


/*************************************************************************************************************************
 Class implementation for PLCCommand
**************************************************************************************************************************/

/*************************************************************************************************************************
 Class implementation for Driver_S7Net
**************************************************************************************************************************/
LibMCDriver_S7NetResult libmcdriver_s7net_driver_s7net_connect(LibMCDriver_S7Net_Driver_S7Net pDriver_S7Net, eLibMCDriver_S7NetS7CPUType eCPUType, const char * pIPAddress, LibMCDriver_S7Net_uint32 nRack, LibMCDriver_S7Net_uint32 nSlot)
{
	IBase* pIBaseClass = (IBase *)pDriver_S7Net;

	try {
		if (pIPAddress == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sIPAddress(pIPAddress);
		IDriver_S7Net* pIDriver_S7Net = dynamic_cast<IDriver_S7Net*>(pIBaseClass);
		if (!pIDriver_S7Net)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		pIDriver_S7Net->Connect(eCPUType, sIPAddress, nRack, nSlot);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_s7net_disconnect(LibMCDriver_S7Net_Driver_S7Net pDriver_S7Net)
{
	IBase* pIBaseClass = (IBase *)pDriver_S7Net;

	try {
		IDriver_S7Net* pIDriver_S7Net = dynamic_cast<IDriver_S7Net*>(pIBaseClass);
		if (!pIDriver_S7Net)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		pIDriver_S7Net->Disconnect();

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_s7net_createcommand(LibMCDriver_S7Net_Driver_S7Net pDriver_S7Net, const char * pCommand, LibMCDriver_S7Net_PLCCommand * pPLCCommand)
{
	IBase* pIBaseClass = (IBase *)pDriver_S7Net;

	try {
		if (pCommand == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (pPLCCommand == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sCommand(pCommand);
		IBase* pBasePLCCommand(nullptr);
		IDriver_S7Net* pIDriver_S7Net = dynamic_cast<IDriver_S7Net*>(pIBaseClass);
		if (!pIDriver_S7Net)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		pBasePLCCommand = pIDriver_S7Net->CreateCommand(sCommand);

		*pPLCCommand = (IBase*)(pBasePLCCommand);
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_s7net_executecommand(LibMCDriver_S7Net_Driver_S7Net pDriver_S7Net, LibMCDriver_S7Net_PLCCommand pPLCCommand)
{
	IBase* pIBaseClass = (IBase *)pDriver_S7Net;

	try {
		IBase* pIBaseClassPLCCommand = (IBase *)pPLCCommand;
		IPLCCommand* pIPLCCommand = dynamic_cast<IPLCCommand*>(pIBaseClassPLCCommand);
		if (!pIPLCCommand)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		IDriver_S7Net* pIDriver_S7Net = dynamic_cast<IDriver_S7Net*>(pIBaseClass);
		if (!pIDriver_S7Net)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		pIDriver_S7Net->ExecuteCommand(pIPLCCommand);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_driver_s7net_waitforcommand(LibMCDriver_S7Net_Driver_S7Net pDriver_S7Net, LibMCDriver_S7Net_PLCCommand pPLCCommand, LibMCDriver_S7Net_uint32 nReactionTimeInMS, LibMCDriver_S7Net_uint32 nWaitForTimeInMS, bool * pCommandSuccess)
{
	IBase* pIBaseClass = (IBase *)pDriver_S7Net;

	try {
		if (pCommandSuccess == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		IBase* pIBaseClassPLCCommand = (IBase *)pPLCCommand;
		IPLCCommand* pIPLCCommand = dynamic_cast<IPLCCommand*>(pIBaseClassPLCCommand);
		if (!pIPLCCommand)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		IDriver_S7Net* pIDriver_S7Net = dynamic_cast<IDriver_S7Net*>(pIBaseClass);
		if (!pIDriver_S7Net)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		*pCommandSuccess = pIDriver_S7Net->WaitForCommand(pIPLCCommand, nReactionTimeInMS, nWaitForTimeInMS);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}



/*************************************************************************************************************************
 Function table lookup implementation
**************************************************************************************************************************/

LibMCDriver_S7NetResult LibMCDriver_S7Net::Impl::LibMCDriver_S7Net_GetProcAddress (const char * pProcName, void ** ppProcAddress)
{
	if (pProcName == nullptr)
		return LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM;
	if (ppProcAddress == nullptr)
		return LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM;
	*ppProcAddress = nullptr;
	std::string sProcName (pProcName);
	
	if (sProcName == "libmcdriver_s7net_driver_configure") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_configure;
	if (sProcName == "libmcdriver_s7net_driver_getname") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_getname;
	if (sProcName == "libmcdriver_s7net_driver_gettype") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_gettype;
	if (sProcName == "libmcdriver_s7net_driver_getversion") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_getversion;
	if (sProcName == "libmcdriver_s7net_driver_getheaderinformation") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_getheaderinformation;
	if (sProcName == "libmcdriver_s7net_driver_queryparameters") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_queryparameters;
	if (sProcName == "libmcdriver_s7net_driver_s7net_connect") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_s7net_connect;
	if (sProcName == "libmcdriver_s7net_driver_s7net_disconnect") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_s7net_disconnect;
	if (sProcName == "libmcdriver_s7net_driver_s7net_createcommand") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_s7net_createcommand;
	if (sProcName == "libmcdriver_s7net_driver_s7net_executecommand") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_s7net_executecommand;
	if (sProcName == "libmcdriver_s7net_driver_s7net_waitforcommand") 
		*ppProcAddress = (void*) &libmcdriver_s7net_driver_s7net_waitforcommand;
	if (sProcName == "libmcdriver_s7net_getversion") 
		*ppProcAddress = (void*) &libmcdriver_s7net_getversion;
	if (sProcName == "libmcdriver_s7net_getlasterror") 
		*ppProcAddress = (void*) &libmcdriver_s7net_getlasterror;
	if (sProcName == "libmcdriver_s7net_releaseinstance") 
		*ppProcAddress = (void*) &libmcdriver_s7net_releaseinstance;
	if (sProcName == "libmcdriver_s7net_acquireinstance") 
		*ppProcAddress = (void*) &libmcdriver_s7net_acquireinstance;
	if (sProcName == "libmcdriver_s7net_injectcomponent") 
		*ppProcAddress = (void*) &libmcdriver_s7net_injectcomponent;
	if (sProcName == "libmcdriver_s7net_getsymbollookupmethod") 
		*ppProcAddress = (void*) &libmcdriver_s7net_getsymbollookupmethod;
	if (sProcName == "libmcdriver_s7net_createdriver") 
		*ppProcAddress = (void*) &libmcdriver_s7net_createdriver;
	
	if (*ppProcAddress == nullptr) 
		return LIBMCDRIVER_S7NET_ERROR_COULDNOTFINDLIBRARYEXPORT;
	return LIBMCDRIVER_S7NET_SUCCESS;
}

/*************************************************************************************************************************
 Global functions implementation
**************************************************************************************************************************/
LibMCDriver_S7NetResult libmcdriver_s7net_getversion(LibMCDriver_S7Net_uint32 * pMajor, LibMCDriver_S7Net_uint32 * pMinor, LibMCDriver_S7Net_uint32 * pMicro)
{
	IBase* pIBaseClass = nullptr;

	try {
		if (!pMajor)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (!pMinor)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (!pMicro)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		CWrapper::GetVersion(*pMajor, *pMinor, *pMicro);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_getlasterror(LibMCDriver_S7Net_Base pInstance, const LibMCDriver_S7Net_uint32 nErrorMessageBufferSize, LibMCDriver_S7Net_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError)
{
	IBase* pIBaseClass = nullptr;

	try {
		if ( (!pErrorMessageBuffer) && !(pErrorMessageNeededChars) )
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (pHasError == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		IBase* pIBaseClassInstance = (IBase *)pInstance;
		IBase* pIInstance = dynamic_cast<IBase*>(pIBaseClassInstance);
		if (!pIInstance)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		std::string sErrorMessage("");
		*pHasError = CWrapper::GetLastError(pIInstance, sErrorMessage);

		if (pErrorMessageNeededChars)
			*pErrorMessageNeededChars = (LibMCDriver_S7Net_uint32) (sErrorMessage.size()+1);
		if (pErrorMessageBuffer) {
			if (sErrorMessage.size() >= nErrorMessageBufferSize)
				throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_BUFFERTOOSMALL);
			for (size_t iErrorMessage = 0; iErrorMessage < sErrorMessage.size(); iErrorMessage++)
				pErrorMessageBuffer[iErrorMessage] = sErrorMessage[iErrorMessage];
			pErrorMessageBuffer[sErrorMessage.size()] = 0;
		}
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_releaseinstance(LibMCDriver_S7Net_Base pInstance)
{
	IBase* pIBaseClass = nullptr;

	try {
		IBase* pIBaseClassInstance = (IBase *)pInstance;
		IBase* pIInstance = dynamic_cast<IBase*>(pIBaseClassInstance);
		if (!pIInstance)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		CWrapper::ReleaseInstance(pIInstance);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_acquireinstance(LibMCDriver_S7Net_Base pInstance)
{
	IBase* pIBaseClass = nullptr;

	try {
		IBase* pIBaseClassInstance = (IBase *)pInstance;
		IBase* pIInstance = dynamic_cast<IBase*>(pIBaseClassInstance);
		if (!pIInstance)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		CWrapper::AcquireInstance(pIInstance);

		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_injectcomponent(const char * pNameSpace, LibMCDriver_S7Net_pvoid pSymbolAddressMethod)
{
	IBase* pIBaseClass = nullptr;

	try {
		if (pNameSpace == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sNameSpace(pNameSpace);
		
		bool bNameSpaceFound = false;
		
		if (sNameSpace == "LibMCEnv") {
			if (CWrapper::sPLibMCEnvWrapper.get() != nullptr) {
				throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_COULDNOTLOADLIBRARY);
			}
			CWrapper::sPLibMCEnvWrapper = LibMCEnv::CWrapper::loadLibraryFromSymbolLookupMethod(pSymbolAddressMethod);
			bNameSpaceFound = true;
		}
		
		if (!bNameSpaceFound)
			throw ELibMCDriver_S7NetInterfaceException(LIBMCDRIVER_S7NET_ERROR_COULDNOTLOADLIBRARY);
		
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_getsymbollookupmethod(LibMCDriver_S7Net_pvoid * pSymbolLookupMethod)
{
	IBase* pIBaseClass = nullptr;

	try {
		if (pSymbolLookupMethod == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		*pSymbolLookupMethod = (void*)&LibMCDriver_S7Net::Impl::LibMCDriver_S7Net_GetProcAddress;
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}

LibMCDriver_S7NetResult libmcdriver_s7net_createdriver(const char * pName, const char * pType, LibMCEnv_DriverEnvironment pDriverEnvironment, LibMCDriver_S7Net_Driver * pInstance)
{
	IBase* pIBaseClass = nullptr;

	try {
		if (pName == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (pType == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		if (pInstance == nullptr)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDPARAM);
		std::string sName(pName);
		std::string sType(pType);
		LibMCEnv::PDriverEnvironment pIDriverEnvironment = std::make_shared<LibMCEnv::CDriverEnvironment>(CWrapper::sPLibMCEnvWrapper.get(), pDriverEnvironment);
		CWrapper::sPLibMCEnvWrapper->AcquireInstance(pIDriverEnvironment.get());
		if (!pIDriverEnvironment)
			throw ELibMCDriver_S7NetInterfaceException (LIBMCDRIVER_S7NET_ERROR_INVALIDCAST);
		
		IBase* pBaseInstance(nullptr);
		pBaseInstance = CWrapper::CreateDriver(sName, sType, pIDriverEnvironment);

		*pInstance = (IBase*)(pBaseInstance);
		return LIBMCDRIVER_S7NET_SUCCESS;
	}
	catch (ELibMCDriver_S7NetInterfaceException & Exception) {
		return handleLibMCDriver_S7NetException(pIBaseClass, Exception);
	}
	catch (std::exception & StdException) {
		return handleStdException(pIBaseClass, StdException);
	}
	catch (...) {
		return handleUnhandledException(pIBaseClass);
	}
}


