#include "TciTM/TriTciChannel.h"
#include "TciTM/TriTciCallStack.h"
#include "TciTM/EncDecTriTci.h"

#ifdef _WIN32
#include <winsock2.h>
#include <Ws2tcpip.h>
#include "Shared/WSAError.h"

#ifdef _WIN32
	#ifdef _MSC_VER
		#if _MSC_VER >= 1600
			#include <stdint.h>
		#else
			typedef int int32_t;
		#endif
	#else
		#include <stdint.h>
	#endif
#else
#include <stdint.h>
#endif

#define SOCKET_TYPE SOCKET // Defines compiler-specific socket handle type
#define SOCKET_CALL_ERROR INVALID_SOCKET // Defines compiler-specific error value of some socket functions
#define CLOSE_SOCKET closesocket // Defines compiler-specific function for closing sockets
#define THREAD_HANDLE HANDLE
static HANDLE evSent;
#else // currently optimised for gcc
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#include <sys/errno.h>
#include <string.h>
#include <stdlib.h>
#define SOCKET_TYPE int // Defines compiler-specific socket handle type
#define SOCKET_CALL_ERROR -1 // Defines compiler-specific error value of some socket functions
#define CLOSE_SOCKET close // Defines compiler-specific function for closing sockets
#define THREAD_HANDLE pthread_t
#define SOCKET_ERROR -1
static pthread_mutex_t mtxSendingLock = PTHREAD_MUTEX_INITIALIZER;
#endif 
static THREAD_HANDLE hThread;
static int nConnected = 0;
static SOCKET_TYPE hSocket = SOCKET_CALL_ERROR;
static TriTciCallStackRegister m_callStackRegister;
const int VERSION = 4;

const int TCI_VERDICT_NONE = 0;
const int TCI_VERDICT_PASS = 1;
const int TCI_VERDICT_INCONC = 2;
const int TCI_VERDICT_FAIL = 3;
const int TCI_VERDICT_ERROR = 4;
const int TCI_VERDICT_USER_ERROR = 5;

const int TCI_INACTIVE_C = 0;
const int TCI_RUNNING_C = 1;
const int TCI_STOPPED_C = 2;
const int TCI_KILLED_C = 3;
const int TCI_NULL_C = 4;

const int TCI_RUNNING_T = 0;
const int TCI_INACTIVE_T = 1;
const int TCI_EXPIRED_T = 2;
const int TCI_NULL_T = 3;

const int TCI_OK = 0;
const int TCI_ERROR = -1;

// Message codes
enum ETriMessageCode
{
	// CAUTION!!! It is not allowed to delete elements of this enum or
	// change their order. It would have disastrous impact on the deserialisation
	// procedure
	ReservedMsgCode, HelloMsgCode, AckMsgCode, SAResetMsgCode, ExecuteTestCaseMsgCode, MapMsgCode, 
	UnmapMsgCode, SendMsgCode, SendBCMsgCode, SendMCMsgCode, EnqueueMsgCode, SutActionMsgCode, 
	PAResetMsgCode, ExternalFunctionMsgCode, FunctionAckMsgCode, TimerStartMsgCode, TimerStopMsgCode, 
	TimerReadMsgCode, TimerReadAckMsgCode, TimerRunningMsgCode, TimerRunningAckMsgCode, 
	TimerTimeoutMsgCode, CallMsgCode, CallBCMsgCode, CallMCMsgCode,	EndTestCaseMsgCode,
	ReplyMsgCode, ReplyBCMsgCode, ReplyMCMsgCode, EnqueueCallMsgCode, EnqueueReplyMsgCode, 
	RaiseMsgCode, RaiseBCMsgCode, RaiseMCMsgCode, EnqueueExceptionMsgCode,
	// TCI-TM
	RootModuleMsgCode, GetImportedModulesMsgCode, GetModuleParametersMsgCode, GetTestCasesMsgCode, 
	GetTestCaseParametersMsgCode, GetTestCaseTsiMsgCode, StartTestCaseMsgCode, StopTestCaseMsgCode,
	StartControlMsgCode, StopControlMsgCode, TestCaseStartedMsgCode, TestCaseTerminatedMsgCode,
	ControlTerminatedMsgCode, GetModuleParMsgCode, TciLogMsgCode, TciErrorMsgCode,
	GetImportedModulesReplyMsgCode, GetModuleParametersReplyMsgCode, GetTestCasesReplyMsgCode, 
	GetTestCaseParamReplyMsgCode, GetTestCaseTsiReplyMsgCode,
	// TCI-Type
	GetDefiningModuleMsgCode, GetTypeNameMsgCode, GetTypeClassMsgCode, NewInstanceMsgCode,
	GetTypeEncodingMsgCode, GetTypeVariantMsgCode, GetTypeExtensionMsgCode, GetDefiningModuleReplyMsgCode,
	UStringReplyMsgCode, NumericReplyMsgCode, GetTypeExtensionReplyMsgCode,
	// TCI-Value
    UnregisterTciObjectMsgCode, GetValueTypeMsgCode, GetNotPresentMsgCode, GetValueEncodingMsgCode,
	GetValueVariantMsgCode, IsValueEqualMsgCode, IsValueLessMsgCode, GetIntegerValueMsgCode,
	SetIntegerValueMsgCode, GetIntegerStringMsgCode, SetIntegerStringMsgCode, GetAbsIntegerValueMsgCode,
	SetAbsIntegerValueMsgCode, GetIntegerLengthMsgCode, SetIntegerLengthMsgCode, GetIntegerSignMsgCode,
	SetIntegerSignMsgCode, GetDigitAtMsgCode, SetDigitAtMsgCode, GetFloatValueMsgCode, SetFloatValueMsgCode,
	GetFloatStringMsgCode, SetFloatStringMsgCode, GetBoolValueMsgCode, SetBoolValueMsgCode, GetCharValueMsgCode,
	SetCharValueMsgCode, GetCStringValueMsgCode, SetCStringValueMsgCode, GetCharAtMsgCode, SetCharAtMsgCode,
	GetCStringLengthMsgCode, SetCStringLengthMsgCode, GetBStringValueMsgCode, SetBStringValueMsgCode,
	GetBitAtMsgCode, SetBitAtMsgCode, GetBStringLengthMsgCode, SetBStringLengthMsgCode, GetHStringValueMsgCode,
	SetHStringValueMsgCode, GetHexAtMsgCode, SetHexAtMsgCode, GetHStringLengthMsgCode, SetHStringLengthMsgCode,
	GetOStringValueMsgCode, SetOStringValueMsgCode, GetOctetAtMsgCode, SetOctetAtMsgCode,
	GetOStringLengthMsgCode, SetOStringLengthMsgCode, GetUCharValueMsgCode, SetUCharValueMsgCode,
	GetUStringValueMsgCode,	SetUStringValueMsgCode, GetUCharAtMsgCode, SetUCharAtMsgCode,
	GetUStringLengthMsgCode, SetUStringLengthMsgCode, GetUStringBufferMsgCode, SetUStringBufferMsgCode,
	GetEnumValueMsgCode, SetEnumValueMsgCode, GetVerdictValueMsgCode, SetVerdictValueMsgCode,
	GetRecordItemValueMsgCode, SetRecordItemValueMsgCode, GetRecordFieldNamesMsgCode, SetFieldOmittedMsgCode,
	GetUnionItemValueMsgCode, SetUnionItemValueMsgCode, GetVariantNamesMsgCode, PresentVariantNameMsgCode,
	GetRecordOfItemMsgCode, SetRecordOfItemMsgCode, AppendRecordOfItemMsgCode, GetRecordOfElementTypeMsgCode,
	GetRecordOfLengthMsgCode, SetRecordOfLengthMsgCode,	GetRecordOfOffsetMsgCode, GetAddressValueMsgCode,
	SetAddressValueMsgCode, GetObjidValueMsgCode, SetObjidValueMsgCode, GetNamedTypeMsgCode, TciErrorReqMsgCode,
	ValueReplyMsgCode, TypeReplyMsgCode, BoolReplyMsgCode, LongIntReplyMsgCode, DoubleReplyMsgCode,
	ByteReplyMsgCode, UIntReplyMsgCode, SimpleStringReplyMsgCode, StringArrayReplyMsgCode, ObjidReplyMsgCode,
	UStringBufferReplyMsgCode, CloneValueMsgCode, 
	Decode, Encode, EncodeReply,
	SIwriteToTCLogMsgCode, 
	TriMessageReplyMsgCode,
	GetEnumIntValueMsgCode, SetEnumIntValueMsgCode,
	// Keep MaxMessageCode at the end as the last item!!!
	MaxMessageCode
};

// SA callbacks
extern FTriSAReset pTriSAResetCallback;
extern FTriExecuteTestCase pTriExecuteTestCaseCallback;
extern FTriMap pTriMapCallback;
extern FTriUnmap pTriUnmapCallback;
extern FTriEndTestCase pTriEndTestCaseCallback;
extern FTriSend pTriSendCallback;
extern FTriSendBC pTriSendBCCallback;
extern FTriSendMC pTriSendMCCallback;
extern FTriCall pTriCallCallback;
extern FTriCallBC pTriCallBCCallback;
extern FTriCallMC pTriCallMCCallback;
extern FTriReply pTriReplyCallback;
extern FTriReplyBC pTriReplyBCCallback;
extern FTriReplyMC pTriReplyMCCallback;
extern FTriRaise pTriRaiseCallback;
extern FTriRaiseBC pTriRaiseBCCallback;
extern FTriRaiseMC pTriRaiseMCCallback;
extern FTriSUTActionInformal pTriSUTActionInformalCallback;

// PA callbacks
extern FTriPAReset pTriPAResetCallback;
extern FTriStartTimer pTriStartTimerCallback;
extern FTriStopTimer pTriStopTimerCallback;
extern FTriReadTimer pTriReadTimerCallback;
extern FTriTimerRunning pTriTimerRunningCallback;
extern FTriExternalFunction pTriExternalFunctionCallback;

// Service callbacks
extern FOnError pOnErrorCallback;
extern FOnConnectionEstablished pOnConnectionEstablishedCallback;
extern FOnConnectionClosed pOnConnectionClosedCallback;

//TM callbacks

static FTciTMTestCaseStarted pTciTMTCStartedCallback = NULL;
static FTciTMTestCaseTerminated pTciTMTCTerminatedCallback = NULL;
static FTciTMControlTerminated pTciTMCtrlTerminatedCallback = NULL;
static FTciTMGetModulePar pTciTMGetModParCallback = NULL;
static FTciTMLog pTciTMLogCallback = NULL;
static FTciTMError pTciTMErrorCallback = NULL;

static void closeLocalSocket()
{
#ifdef _WIN32
	WaitForSingleObject(evSent, INFINITE);
#else
	pthread_mutex_lock(&mtxSendingLock);
#endif
	if (hSocket != SOCKET_CALL_ERROR)
	{
		shutdown(hSocket, 2); // Win:SD_BOTH, Linux:SHUT_RDWR
		CLOSE_SOCKET(hSocket);
		hSocket = SOCKET_CALL_ERROR;
		if (nConnected && pOnConnectionClosedCallback)
			pOnConnectionClosedCallback();
		nConnected = 0;
		disposeCallStackRegister(&m_callStackRegister);
	}
#ifdef _WIN32
	SetEvent(evSent);
#else
	pthread_mutex_unlock(&mtxSendingLock);
#endif
}

static void onError(char * pszErrorMsg)
{
	if (pOnErrorCallback)
		pOnErrorCallback(pszErrorMsg);
	closeLocalSocket();
}

static void onWSAError(char * pszErrorMsg)

{	
	char szBuf [100];
#ifdef _WIN32
	char * pszErr = getWSAErrorString();
#ifdef _MSC_VER
	sprintf_s(szBuf, 100, pszErrorMsg, pszErr);
#else
	sprintf(szBuf, pszErrorMsg, pszErr);
#endif
#else
	sprintf(szBuf, pszErrorMsg, "");
#endif
	onError(szBuf);	
}
/////////////////////////////TCI specific stuff starts here...
void copyTciTestCaseIdList(TciTestCaseIdListType * pTargetList, const TciTestCaseIdListType * pSrcList)
{
	int i;
	pTargetList->length = pSrcList->length;
	pTargetList->idList = (QualifiedName *)malloc(pSrcList->length * sizeof(QualifiedName));
	for(i = 0; i < pSrcList->length; i++)
	{
		copyQualifiedName(&pTargetList->idList[i], &pSrcList->idList[i]);
	}
}

void copyTciModuleIdList(TciModuleIdListType * pTargetList, const TciModuleIdListType * pSrcList)
{
	copyTciTestCaseIdList(pTargetList, pSrcList);
}

void clearTciTestCaseIdList(TciTestCaseIdListType * pList)
{
	int i;
	for(i = 0;i<pList->length;i++)
	{
		free(pList->idList[i].moduleName);
		free(pList->idList[i].objectName);
	}
	free(pList->idList);
	memset(pList, 0, sizeof(TciTestCaseIdListType));
}

void clearTciModuleIdList(TciModuleIdListType * pList)
{
	clearTciTestCaseIdList(pList);
}

void clearObjectidValue(TciObjidValue * pObjidVal)
{
	unsigned long i;
	for(i = 0; i < pObjidVal->length; i++)
	{
		TciObjidElemValue *elem = &pObjidVal->elements[i];
		free(elem->elem_as_ascii);
	}
	free(pObjidVal->elements);
	memset(pObjidVal, 0, sizeof(TciObjidValue));
}

void clearCString(TciCharStringValue * pCString)
{
	free(pCString->string);
	memset(pCString, 0, sizeof(TciCharStringValue));
}

void clearUCString(TciUCStringValue *pUCString)
{
	free(pUCString->string);
	memset(pUCString, 0, sizeof(TciUCStringValue));
}

void clearTciParameterType(TciParameterType *parType)
{
	free(parType->parName);
	disposeTciValue(parType->parValue);
	memset(parType, 0, sizeof(TciParameterType));
}

void clearTciParamList(TciParameterListType * parList)
{
	long i;
	for(i = 0; i < parList->length; i++)
	{
		clearTciParameterType(&parList->parList[i]);
	}
	free(parList->parList);
	memset(parList, 0, sizeof(TciParameterListType));
}

void clearTestCaseIdList(TciTestCaseIdListType *pTcList)
{
	long i;
	for(i = 0 ;i < pTcList->length;i++)
		clearQualifiedName(&pTcList->idList[i]);
	free(pTcList->idList);
	memset(pTcList, 0, sizeof(TciTestCaseIdListType));
}

void clearStringArray(String ** paStr)
{
	int i = 0;
	String * arr  = *paStr;
	while(arr[i])
		free(arr[i++]);
	free(arr);
	*paStr = 0;
}

void clearTciParameterTypeType(TciParameterTypeType *pParTypeType)
{
	disposeTciType(pParTypeType->parameterType);
	memset(pParTypeType, 0, sizeof(TciParameterTypeType));
}

void clearTciParameterTypeList(TciParameterTypeListType *pParTypeList)
{
	long i;
	for(i = 0; i < pParTypeList->length; i++)
		clearTciParameterTypeType(&pParTypeList->parList[i]);
	free(pParTypeList->parList);
	memset(pParTypeList, 0, sizeof(TciParameterTypeListType));
}

void clearTciModuleParameterList(TciModuleParameterListType * pModParList)
{
	long i;
	for(i = 0; i < pModParList->length;i++)
	{
		TciModuleParameterType *pMT = &pModParList->modParList[i];
		disposeTciValue(pMT->defaultValue);
		free(pMT->parName);
	}
	free(pModParList->modParList);
	memset(pModParList, 0, sizeof(TciModuleParameterListType));
}

int sendData (char * pData, int nLen)
{
	int nRes = send(hSocket, pData, nLen, 0);
	int nOk = nRes != SOCKET_ERROR;
	if (!nOk)
	{
		onWSAError("Sending failed (%s)");
	}
	return nOk;
}

static void sendMessage (int nMsgCode, int nLen, char * pData)
{
	char * pBuf;
#ifdef _WIN32
	WaitForSingleObject(evSent, INFINITE);
#else
	pthread_mutex_lock(&mtxSendingLock);
#endif
	if (hSocket != SOCKET_CALL_ERROR)
	{
		pBuf = (char*)malloc(9);
		pBuf[0] = (char)0x80;
		memcpy(&pBuf[1], &nMsgCode, 4);
		memcpy(&pBuf[5], &nLen, 4);

		if (sendData(pBuf, 9))
			sendData(pData, nLen);
		free(pBuf);
	}
#ifdef _WIN32
	SetEvent(evSent);
#else
	pthread_mutex_unlock(&mtxSendingLock);
#endif
}

static AbstractTriAckMessage* sendMessageWithAck(int nMsgCode, int nLen, char * pData, int requiredAck)
{
	AbstractTriAckMessage * res = 0;
	TriTciCallData * callData = registerCall(&m_callStackRegister, pData, requiredAck, 50000);
	sendMessage(nMsgCode, nLen, pData);

	if(callData)
		res = waitForAck(callData);

	if(!res)
	{
		unregisterCall(&m_callStackRegister);
		onError("No acknowledgement received for a TM call.");
	}
	return res;
}

#ifdef _WIN32
static DWORD WINAPI receiveMessage(LPVOID par)
#else
static void * receiveMessage(void * par)
#endif
{
	int nSendAck, nFormatError = 0;
	int nLocalId = -1;
	AbstractTriTciMessage *msg = (AbstractTriTciMessage *)par;
	int nMsgCode = msg->messageCode;
	const char * pData = msg->pData;
	int nLen = msg->nLen;
	TriStatus status = TRI_OK;
	msg->nLocalId = -1;
	msg->nServerId = -1;
	msg->nSourceThreadId = -1;
	if(nLen >= HEADER_V3_LENGTH)
	{
		decodeInt(&msg->nServerId, pData, nLen, 0);
		decodeInt(&msg->nLocalId, pData, nLen, 4);
	}
	
	if(acceptMessage(&m_callStackRegister, msg))
	{
		disposeAbstractMsg(msg);
		return 0;
	}
	nLocalId = saveRemoteId(&m_callStackRegister, msg->nServerId, msg->nLocalId);
	if ((nSendAck = nMsgCode == SAResetMsgCode))
	{
		if ((nFormatError = nLen > HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else if (pTriSAResetCallback)
			status = pTriSAResetCallback();
	}
	else if ((nSendAck = nMsgCode == ExecuteTestCaseMsgCode))
	{
		if ((nFormatError  = nLen == HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else
		{
			int nOffset = HEADER_V3_LENGTH;
			if ((nFormatError = nOffset < HEADER_V3_LENGTH))
				status = TRI_ERROR;
			else
			{
				TriTestCaseId testCaseId;
				TriPortIdList tsiPortList;

				memset(&testCaseId, 0, sizeof(testCaseId));
				memset(&tsiPortList, 0, sizeof(tsiPortList));
				nOffset = decodeQualifiedName(&testCaseId, pData, nLen, nOffset);
				if (nOffset >= 0)
					nOffset = decodePortList(&tsiPortList, pData, nLen, nOffset);
				if ((nFormatError = nOffset < 0))
					status = TRI_ERROR;
				else if (pTriExecuteTestCaseCallback)
					status = pTriExecuteTestCaseCallback(&testCaseId, &tsiPortList);
				clearQualifiedName(&testCaseId);
				clearTriPortIdList(&tsiPortList);
			}
		}
	}
	else if ((nSendAck = nMsgCode == MapMsgCode || nMsgCode == UnmapMsgCode))
	{
		if ((nFormatError  = nLen == HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else
		{
			int nOffset = HEADER_V3_LENGTH;
			TriPortId compPort, tsiPort;

			memset(&compPort, 0, sizeof(compPort));
			memset(&tsiPort, 0, sizeof(tsiPort));
			nOffset = decodePortId(&compPort, pData, nLen, nOffset);
			if (nOffset >= 0)
				nOffset = decodePortId(&tsiPort, pData, nLen, nOffset);
			if ((nFormatError = nOffset < 0))
				status = TRI_ERROR;
			else
			{
				if (nMsgCode == MapMsgCode)
				{
					if (pTriMapCallback)
						status = pTriMapCallback(&compPort, &tsiPort);
				}
				else
				{
					if (pTriUnmapCallback)
						status = pTriUnmapCallback(&compPort, &tsiPort);
				}
			}
			clearTriPortId(&compPort);
			clearTriPortId(&tsiPort);
		}
	}
	else if ((nSendAck =  nMsgCode == SendMsgCode || nMsgCode == SendBCMsgCode || nMsgCode == SendMCMsgCode ||
		nMsgCode == CallMsgCode || nMsgCode == CallBCMsgCode || nMsgCode == CallMCMsgCode ||
		nMsgCode == ReplyMsgCode || nMsgCode == ReplyBCMsgCode || nMsgCode == ReplyMCMsgCode ||
		nMsgCode == RaiseMsgCode || nMsgCode == RaiseBCMsgCode || nMsgCode == RaiseMCMsgCode))
	{
		if ((nFormatError  = nLen == HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else
		{
			int nOffset = HEADER_V3_LENGTH;
			TriComponentId componentId;
			TriPortId tsiPortId;
			TriAddress address;
			TriAddressList addrList;

			memset(&componentId, 0, sizeof(componentId));			
			memset(&tsiPortId, 0, sizeof(tsiPortId));
			memset(&address, 0, sizeof(address));
			memset(&addrList, 0, sizeof(addrList));

			nOffset = decodeCompId(&componentId, pData, nLen, nOffset);
			if (nOffset >= 0)
				nOffset = decodePortId(&tsiPortId, pData, nLen, nOffset);

			if (nOffset >= 0)
			{
				if (nMsgCode == SendMsgCode || nMsgCode == CallMsgCode || nMsgCode == ReplyMsgCode ||
					nMsgCode == RaiseMsgCode)
					nOffset = decodeBinaryString(&address, pData, nLen, nOffset, -1);
				else if (nMsgCode == SendMCMsgCode || nMsgCode == CallMCMsgCode ||
					nMsgCode == ReplyMCMsgCode || nMsgCode == RaiseMCMsgCode)
					nOffset = decodeAddrList(&addrList, pData, nLen, nOffset);
			}

			if (nOffset >= 0)
			{
				if (nMsgCode == SendMsgCode || nMsgCode == SendBCMsgCode || nMsgCode == SendMCMsgCode)
				{
					TriMessage sendMessage;
					nOffset = decodeBinaryString(&sendMessage, pData, nLen, nOffset, -1);
					if (nOffset >= 0)
					{
						if (nMsgCode == SendMsgCode)
						{
							if (pTriSendCallback)
								status = pTriSendCallback(&componentId, &tsiPortId, &address, &sendMessage);
						}
						else if (nMsgCode == SendBCMsgCode)
						{
							if (pTriSendBCCallback)
							status = pTriSendBCCallback(&componentId, &tsiPortId, &sendMessage);
						}
						else
						{
							if (pTriSendMCCallback)
								status = pTriSendMCCallback(&componentId, &tsiPortId, &addrList, &sendMessage);
						}
					}
					clearBinaryString(&sendMessage);
				}
				else
				{
					TriSignatureId signId;
					memset(&signId, 0, sizeof(signId));
					nOffset = decodeQualifiedName(&signId, pData, nLen, nOffset);

					if (nMsgCode == CallMsgCode || nMsgCode == CallBCMsgCode || nMsgCode == CallMCMsgCode ||
						nMsgCode == ReplyMsgCode || nMsgCode == ReplyBCMsgCode || nMsgCode == ReplyMCMsgCode)
					{
						TriParameterList paramList;
						TriParameter returnValue;
						char** plsParNames = 0;
						char* pszParName = 0;
						int i;
						memset(&paramList, 0, sizeof(paramList));
						memset(&returnValue, 0, sizeof(returnValue));

						nOffset = decodeParamList(&paramList, &plsParNames, pData, nLen, nOffset);
						
						for(i=0;i<paramList.length;i++)
							free(plsParNames[i]);
						free(plsParNames);//not used

						if (nOffset >=0 && (nMsgCode == ReplyMsgCode || nMsgCode == ReplyBCMsgCode || nMsgCode == ReplyMCMsgCode))
							nOffset = decodeParameter(&returnValue, &pszParName, pData, nLen, nOffset);
						free(pszParName);//not used

						if (nOffset >= 0)
						{
							if (nMsgCode == CallMsgCode)
							{
								if (pTriCallCallback)
									status = pTriCallCallback(&componentId, &tsiPortId, &address, &signId, &paramList);
							}
							else if (nMsgCode == CallBCMsgCode)
							{
								if (pTriCallBCCallback)
									status = pTriCallBCCallback(&componentId, &tsiPortId, &signId, &paramList);
							}
							else if (nMsgCode == CallMCMsgCode)
							{
								if (pTriCallMCCallback)
									status = pTriCallMCCallback(&componentId, &tsiPortId, &addrList, &signId, &paramList);
							}
							else if (nMsgCode == ReplyMsgCode)
							{
								if (pTriReplyCallback)
									status = pTriReplyCallback(&componentId, &tsiPortId, &address, &signId, &paramList, &returnValue);
							}
							else if (nMsgCode == ReplyBCMsgCode)
							{
								if (pTriReplyBCCallback)
									status = pTriReplyBCCallback(&componentId, &tsiPortId, &signId, &paramList, &returnValue);
							}
							else
							{
								if (pTriReplyMCCallback)
									status = pTriReplyMCCallback(&componentId, &tsiPortId, &addrList, &signId, &paramList, &returnValue);
							}
						}
						clearTriParameterList(&paramList);
						clearTriParameter(&returnValue);
					}
					else
					{
						TriException exc;
						memset(&exc, 0, sizeof(exc));
						nOffset = decodeBinaryString(&exc, pData, nLen, nOffset, -1);
						if (nOffset >= 0)
						{
							if (nMsgCode == RaiseMsgCode)
							{
								if (pTriRaiseCallback)
									status = pTriRaiseCallback(&componentId, &tsiPortId, &address, &signId, &exc);
							}
							else if (nMsgCode == RaiseBCMsgCode)
							{
								if (pTriRaiseBCCallback)
									status = pTriRaiseBCCallback(&componentId, &tsiPortId, &signId, &exc);
							}
							else
							{
								if (pTriRaiseMCCallback)
									status = pTriRaiseMCCallback(&componentId, &tsiPortId, &addrList, &signId, &exc);
							}
						}
						clearBinaryString(&exc);
					}
					clearQualifiedName(&signId);
				}
			}

			if ((nFormatError = nOffset < 0))
				status = TRI_ERROR;

			clearTriComponentId(&componentId);
			clearTriPortId(&tsiPortId);
			clearBinaryString(&address);
			clearTriAddressList(&addrList);			
		}
	}
	else if ((nSendAck = nMsgCode == SutActionMsgCode))
	{
		if ((nFormatError  = nLen == HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else
		{
			wchar_t * wszDescription = NULL;
			int nOffset = decodeUString(&wszDescription, pData, nLen, HEADER_V3_LENGTH);
			if ((nFormatError = nOffset < 0))
				status = TRI_ERROR;
			else if (pTriSUTActionInformalCallback)
			{
				char * pszDescription = 0;
				if (wszDescription)
				{
					int nStrLen = (int)(wcslen(wszDescription) + 1) * 2;
#ifdef _MSC_VER
					size_t convertedChars;
#endif
					pszDescription = (char*)malloc(nStrLen);
#ifdef _MSC_VER
					wcstombs_s(&convertedChars, pszDescription, nStrLen, wszDescription, nStrLen);
#else
					wcstombs(pszDescription, wszDescription, nStrLen);
#endif
				}
				status = pTriSUTActionInformalCallback(pszDescription);
				free(pszDescription);
			}
			free(wszDescription);
		}
	}
	else if ((nSendAck = nMsgCode == PAResetMsgCode))
	{
		if ((nFormatError  = nLen > HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else if (pTriPAResetCallback)
			status = pTriPAResetCallback();
	}
	else if (nMsgCode == ExternalFunctionMsgCode)
	{
		int nOffset = HEADER_V3_LENGTH;
		TriFunctionId funcId;
		TriParameterList paramList;
		TriParameter returnValue;
		char ** plsParameterNames;

		memset(&funcId, 0, sizeof(funcId));
		memset(&paramList, 0, sizeof(paramList));
		memset(&returnValue, 0, sizeof(returnValue));

		nSendAck = 0; // own ack
		nOffset = decodeQualifiedName(&funcId, pData, nLen, nOffset);
		if (nOffset >= 0)
			nOffset = decodeParamList(&paramList, &plsParameterNames, pData, nLen, nOffset);
		if ((nFormatError = nOffset < 0))
			status = TRI_ERROR;
		else
		{
			TriParameter ** apAllocated;
			TriParameterList replyList;
			char ** pNamesToReturn;
			int i, nAckLength;
			char * pAckData = NULL;
			int nItemsToCheck;

			// save data pointers to check if user allocated any new memory
			apAllocated = (TriParameter**)malloc(sizeof(TriParameter*) * paramList.length);
			memcpy(apAllocated, paramList.parList, sizeof(TriParameter*) * paramList.length);
			nItemsToCheck = paramList.length;

			if (pTriExternalFunctionCallback)
				status = pTriExternalFunctionCallback(&funcId, &paramList, &returnValue);
			
			replyList.length = 0;
			replyList.parList = (TriParameter**)malloc(sizeof(TriParameter*) * paramList.length);
			pNamesToReturn = (char**)malloc(sizeof(char *) * paramList.length);

			for (i = 0; i < paramList.length; i++)
			{
				TriParameter * pParam = paramList.parList[i];
				if (pParam->mode != TRI_IN)
				{
					pNamesToReturn[replyList.length] = plsParameterNames[i];
					replyList.parList[replyList.length++] = pParam;
				}
			}
			nAckLength = HEADER_V3_LENGTH + 1 + 
				calcParamListLen(&replyList, (const char***)&pNamesToReturn) + calcParamLen(&returnValue, 0);
			pAckData = (char *)malloc(nAckLength);
			fillCommunicationIds(&m_callStackRegister, pAckData, -1);
			pAckData[HEADER_V3_LENGTH] = (unsigned char)status;
			nOffset = encodeParamList(&replyList, (const char***)&pNamesToReturn, pAckData, HEADER_V3_LENGTH + 1);
			nOffset = encodeParam(&returnValue, 0, pAckData, nOffset);
			sendMessage(FunctionAckMsgCode, nAckLength, pAckData);
			
			if(paramList.length == nItemsToCheck)//we are in trouble if this does not equal...
			{
				for(i=0; i < nItemsToCheck; i++)
				{
					if(paramList.parList[i] != apAllocated[i])
					{
						free(apAllocated[i]->par.data);
						free(apAllocated[i]);
					}
					else if(paramList.parList[i]->par.data != apAllocated[i]->par.data)
						free(apAllocated[i]->par.data);
				}
			}
			// dispose the data allocated by this function
			clearTriParameterList(&paramList);
			clearTriParameter(&returnValue);
			for(i =0 ; i < nItemsToCheck; i++)
				free(plsParameterNames[i]);
			free(plsParameterNames);	
			free(pNamesToReturn);
			free(replyList.parList);
			free(apAllocated);
			free(paramList.parList);
			free(pAckData);
			clearQualifiedName(&funcId);

			disposeAbstractMsg(msg);
			return 0;
		}
	}
	else if ((nSendAck = nMsgCode == TimerStartMsgCode))
	{
		if ((nFormatError  = nLen == HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else if (pTriStartTimerCallback){
			TriTimerId timerId;
			TriTimerDuration timerDuration;
			int nOffset = HEADER_V3_LENGTH;
			
			memset(&timerId, 0, sizeof(timerId));
			nOffset = decodeBinaryString(&timerId, pData, nLen, nOffset, 0);
			if (nOffset > 0)
				nOffset = decodeTimerDuration(&timerDuration, pData, nLen, nOffset);
			if ((nFormatError = nOffset < 0))
				status = TRI_ERROR;
			else
				status = pTriStartTimerCallback(&timerId, timerDuration);
			clearBinaryString(&timerId);
		}
	}
	else if ((nSendAck = nMsgCode == TimerStopMsgCode))
	{
		if ((nFormatError  = nLen == HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else if (pTriStopTimerCallback){
			TriTimerId timerId;
			int nOffset = HEADER_V3_LENGTH;
			
			memset(&timerId, 0, sizeof(timerId));
			nOffset = decodeBinaryString(&timerId, pData, nLen, nOffset, 0);
			if ((nFormatError = nOffset < 0))
				status = TRI_ERROR;
			else
				status = pTriStopTimerCallback(&timerId);
			clearBinaryString(&timerId);
		}
	}
	else if ((nMsgCode == TimerReadMsgCode))
	{
		nSendAck = 0;//own ack
		if(pTriReadTimerCallback)
		{
			TriTimerId timerId;
			TriTimerDuration timerDuration;
			int nOffset = HEADER_V3_LENGTH, nAckLength;
			char * pAckData = NULL;

			memset(&timerId, 0, sizeof(timerId));
			nOffset = decodeBinaryString(&timerId, pData, nLen, nOffset, 0);
			memset(&timerDuration, 0, sizeof(TriTimerDuration));
			if ((nFormatError  = nOffset < 0))
				status = TRI_ERROR;
			else
				status = pTriReadTimerCallback(&timerId, &timerDuration);

			nAckLength = HEADER_V3_LENGTH + 1 + calcTimerDuration(&timerDuration);
			pAckData = (char *)malloc(nAckLength);

			fillCommunicationIds(&m_callStackRegister, pAckData, -1);
			pAckData[HEADER_V3_LENGTH] = (unsigned char)status;
			nOffset = encodeTimerDuration(&timerDuration, pAckData, HEADER_V3_LENGTH + 1);
			sendMessage(TimerReadAckMsgCode, nAckLength, pAckData);
			
			clearBinaryString(&timerId);
			free(pAckData);

			disposeAbstractMsg(msg);
			return 0;
		}
	}
	else if ((nMsgCode == TimerRunningMsgCode))
	{
		nSendAck = 0;//own ack
		if(pTriTimerRunningCallback)
		{
			TriTimerId timerId;
			unsigned char running = 0x00;
			int nPayloadLength = 1;
			int nOffset = HEADER_V3_LENGTH, nAckLength;
			char * pAckData = NULL;
			
			memset(&timerId, 0, sizeof(timerId));
			nOffset = decodeBinaryString(&timerId, pData, nLen, nOffset, 0);

			if ((nFormatError  = nOffset < 0))
				status = TRI_ERROR;
			else
				status = pTriTimerRunningCallback(&timerId, &running);

			nAckLength = HEADER_V3_LENGTH + 1 + 4 + 1;//status + (int)sizeof(unsigned char) + value(unsigned char)
			pAckData = (char *)malloc(nAckLength);
			
			fillCommunicationIds(&m_callStackRegister, pAckData, -1);
			pAckData[HEADER_V3_LENGTH] = (unsigned char)status;
			
			memcpy(&pAckData[HEADER_V3_LENGTH + 1], &nPayloadLength, sizeof(int32_t));//should be 4
			memcpy(&pAckData[HEADER_V3_LENGTH + 5], &running, sizeof(unsigned char));//should be 1
			sendMessage(TimerRunningAckMsgCode, nAckLength, pAckData);
			
			clearBinaryString(&timerId);
			free(pAckData);

			disposeAbstractMsg(msg);
			return 0;
		}
	}
	else if ((nSendAck = nMsgCode == EndTestCaseMsgCode))
	{
		if ((nFormatError  = nLen > HEADER_V3_LENGTH))
			status = TRI_ERROR;
		else if (pTriEndTestCaseCallback)
			status = pTriEndTestCaseCallback();
	}
	else if ((nSendAck = nMsgCode == TestCaseStartedMsgCode))
	{
		if(pTciTMTCStartedCallback)
		{
			TciTestCaseIdType testCaseId;
			TciParameterListType tciParList;
			double tmr = 0.0f;
			int nOffset = 0;

			memset(&testCaseId, 0, sizeof(testCaseId));
			memset(&tciParList, 0, sizeof(tciParList));
			
			nOffset = HEADER_V3_LENGTH;
			nOffset = decodeQualifiedName(&testCaseId, pData, nLen, nOffset);
			if(pData[nOffset++])
				nOffset = decodeTciParamList(&tciParList, pData, nLen, nOffset);
			nOffset = decodeDouble(&tmr, pData, nLen, nOffset);

			pTciTMTCStartedCallback(testCaseId, tciParList, tmr);
			clearQualifiedName(&testCaseId);
			clearTciParamList(&tciParList);
		}
		status = TRI_OK;
	}
	else if ((nSendAck = nMsgCode == TestCaseTerminatedMsgCode))
	{//void tciTestCaseTerminated (VerdictValue verdict, TciParameterListType parameterlist)
		if(pTciTMTCTerminatedCallback)
		{
			int nOffset = 0;
			VerdictValue ver;
			TciParameterListType tciParList;

			memset(&ver, 0, sizeof(ver));
			memset(&tciParList, 0, sizeof(tciParList));

			nOffset = HEADER_V3_LENGTH;
			nOffset = decodeVerdictValue(&ver, pData, nLen, nOffset);
			nOffset = decodeTciParamList(&tciParList, pData, nLen, nOffset);

			pTciTMTCTerminatedCallback(ver, tciParList);
			disposeTciValue(ver);
			clearTciParamList(&tciParList);
		}
		status = TRI_OK;
	}
	else if ((nSendAck = nMsgCode == ControlTerminatedMsgCode))
	{//void tciControlTerminated()
		if(pTciTMCtrlTerminatedCallback)
			pTciTMCtrlTerminatedCallback();
	}
	else if ((nMsgCode == GetModuleParMsgCode))
	{//Value tciGetModulePar (TciModuleParameterIdType parameterId)
		if(pTciTMGetModParCallback)
		{
			Value val = 0;
			int nOffset = 0, nAckLen = 0;
			char isPresent = 0x00;
			char * pAckData = NULL;
			AbstractTriAckMessage *retMsg;

			TciModuleParameterIdType modulePar;
			memset(&modulePar, 0, sizeof(modulePar));

			nOffset = HEADER_V3_LENGTH;
			nOffset = decodeQualifiedName(&modulePar, pData, nLen, nOffset);
			val = pTciTMGetModParCallback(modulePar);
			clearQualifiedName(&modulePar);


			nAckLen = ACK_HEADER_V3_LENGTH + 1;
			nAckLen += tciIsNull(val) ? 0 : (calcTciValueLen(val) + 4);
			nOffset = HEADER_V3_LENGTH;
			pAckData = (char*)malloc(nAckLen);
			
			pAckData[nOffset++] = TCI_OK;
			isPresent = tciIsNull(val) ? 0x00:0xFF;
			pAckData[nOffset++] = isPresent;

			if(isPresent)
			{
				nOffset = encodeTciValue(val, pAckData, nOffset);
				memset(&pAckData[nOffset], 0, 4);//clsId not sent to TC
			}
			retMsg = sendMessageWithAck(ValueReplyMsgCode, nAckLen, pAckData, AckMsgCode);
			onAck(&m_callStackRegister, retMsg->nLocalId);
			disposeAbstractMsg(retMsg);

			free(pAckData);
			disposeTciValue(val);

			disposeAbstractMsg(msg);
			return 0;
		}
	}
	else if ((nSendAck = nMsgCode == TciLogMsgCode))
	{
		if(pTciTMLogCallback)
		{
			int nOffset = 0;
			char* pStr = 0;
			TriComponentId compId;
			nOffset = HEADER_V3_LENGTH;
			nOffset = decodeCompId(&compId, pData, nLen, nOffset);
			nOffset = decodeString(&pStr, pData, nLen, nOffset);			
			free(compId.compInst.data);
			free(compId.compName);
			free(compId.compType.moduleName);
			free(compId.compType.objectName);
			pTciTMLogCallback(pStr);
			free(pStr);
		}
		status = TRI_OK;
	}
	else if ((nSendAck = nMsgCode == TciErrorMsgCode))
	{
		if(pTciTMErrorCallback)
		{
			int nOffset = 0;
			char* pStr = 0;
			nOffset = HEADER_V3_LENGTH;
			nOffset = decodeString(&pStr, pData, nLen, nOffset);
			pTciTMErrorCallback(pStr);
			free(pStr);
		}
		status = TRI_OK;
	}
	else
	{
		onAck(&m_callStackRegister, msg->nLocalId);
		onError("Unknown message received");
	}
	if (nSendAck)
	{
		char * pAckData = (char*)malloc(ACK_HEADER_V3_LENGTH);
		//this should be called if sendMessage is used
		fillCommunicationIds(&m_callStackRegister, pAckData, -1);
		pAckData[HEADER_V3_LENGTH] = (char)status;
		sendMessage(AckMsgCode, 9, pAckData);
		free(pAckData);
	}
	disposeAbstractMsg(msg);

	if (nFormatError)
		onError("Invalid message format");
	return 0;
}

#ifdef _WIN32
static DWORD WINAPI rcvThreadProc(LPVOID par)
#else
void * rcvThreadProc()
#endif
{
	char hdr [9];
	THREAD_HANDLE hMsgProcessThread;
	AbstractTriTciMessage *msg;
	do 
	{
		int nMsg, nLen;
		char * pData = NULL;
		int nBytesRemaining = 9;
		while(nBytesRemaining > 0)
		{
			int nRcv = recv(hSocket, &hdr[9 - nBytesRemaining], nBytesRemaining, 0);

			if (nRcv == 0)
			{
				closeLocalSocket();
				return 0;
			}
			else if (nRcv == SOCKET_ERROR)
			{
#ifdef _WIN32
				int nErrorCode = WSAGetLastError();
				if (nErrorCode == WSAECONNRESET || nErrorCode == WSAECONNABORTED ||
					nErrorCode == WSAENETRESET)
				{
					closeLocalSocket();
					return 0;
				}
				else
				{
					onWSAError("Error during receiving (%s)");
					return nErrorCode;
				}
#else
				onError("Error during receiving");
				closeLocalSocket();
				return 0;
#endif
			}
			nBytesRemaining -= nRcv;
		}

		if (hdr[0] != (char)0x80)
		{
			onError("Unknown protocol version");
			return 0;
		}
		memcpy(&nMsg, &hdr[1], 4);
		memcpy(&nLen, &hdr[5], 4);
		if (nLen > 0x100000)
		{
			onError("Invalid length - message is too long");
			return 0;
		}
		
		if (nLen > 0)
		{
			nBytesRemaining = nLen;
			pData = (char*)malloc(nLen);
			while(nBytesRemaining > 0)
			{
				int nRcv = recv(hSocket, &pData[nLen - nBytesRemaining], nBytesRemaining, 0);
				if (nRcv == 0 || nRcv == SOCKET_ERROR)
				{
					if (nRcv == 0)
						closeLocalSocket();
					else
						onWSAError("Error during receiving (%s)");
					free(pData);
#ifdef _WIN32
					return nRcv == 0 ? 0 : WSAGetLastError();
#else
					return 0;
#endif
				}
				nBytesRemaining -= nRcv;
			}
		}
		// process message
		msg = malloc(sizeof(AbstractTriTciMessage));
		msg->messageCode = nMsg;
		msg->pData = pData;
		msg->nLen = nLen;
#ifdef _WIN32
	hMsgProcessThread = CreateThread(0, 0, receiveMessage, msg, CREATE_NEW, 0);
#else
	pthread_create( &hMsgProcessThread, NULL, receiveMessage, msg);
#endif
	} while (1);
	return 0;
}


static int init(char * pszAddr, int nPort, int nInterfaceFlags, wchar_t * wszSutName)
{
#ifdef _MSC_VER
	struct addrinfo addr;
	int n;
	char szPort [20];
	struct addrinfo * pRes;
#else
	struct sockaddr_in addr;
	struct hostent *hs;
#endif
	int nRes, nLen;	
	char * pData;
	
	if (hSocket != SOCKET_CALL_ERROR)
	{
		onError("Cannot create two channels");
		return 0;
	}

	hThread = 0;
#ifdef _WIN32
	evSent = CreateEvent(NULL, FALSE, TRUE, NULL);
#endif
	// create SOCKET handle
	if ((hSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_CALL_ERROR)
	{
		onError("Cannot create socket");
		return 0;
	}
#ifdef _MSC_VER
	memset(&addr, 0, sizeof(addr));
	n = sizeof(int);
	getsockopt(hSocket, SOL_SOCKET, SO_TYPE, (char*)&addr.ai_socktype, &n);
	addr.ai_family = PF_INET;
	addr.ai_protocol = IPPROTO_TCP;
	
	_itoa_s(nPort, szPort, 20, 10);

	// get address info	
	nRes = getaddrinfo(pszAddr, szPort, &addr, &pRes);
	if (nRes != 0) 
	{
		onError("Cannot resolve peer address");
		freeaddrinfo(pRes);
		return 0;
	}
	nRes = connect(hSocket, pRes->ai_addr, (int)pRes->ai_addrlen);
	freeaddrinfo(pRes);
#else
	
	hs = gethostbyname(pszAddr);
 	if (!hs) 
	{
		onError("Cannot resolve peer address");
		return 0;
	}
	addr.sin_family = AF_INET;
	addr.sin_port = htons(nPort);
	addr.sin_addr = *((struct in_addr *)hs->h_addr);
	memset(&(addr.sin_zero), 0, 8);

	nRes = connect(hSocket, (struct sockaddr *) &addr, sizeof(addr));
#endif
	if (nRes)
	{
		onWSAError("Connection attempt failed (%s)");
		return 0;
	}
	else if (pOnConnectionEstablishedCallback)
		pOnConnectionEstablishedCallback();

	nConnected = 0xFF;
#ifdef _WIN32
	hThread = CreateThread(0, 0, rcvThreadProc, 0, CREATE_NEW, 0);
#else
	pthread_create( &hThread, NULL, rcvThreadProc, NULL);
#endif

	//ver 3
	nLen = calcUStrLen(wszSutName) + 5;
	pData = (char *)malloc(nLen);
	encodeUString(wszSutName, pData, 0);
	memcpy(&pData[nLen - 5], &VERSION, 4);
	pData[nLen-1] = (char)nInterfaceFlags;
	sendMessage(HelloMsgCode, nLen, pData);
	free(pData);

	initCallStackRegister(&m_callStackRegister);

	return -1;
}

int openDefaultTriTciChannelTimeout(int nInterfaceFlags, wchar_t * wszSutName, unsigned int nTimeout)
{
	int result = init("127.0.0.1", 7777, nInterfaceFlags, wszSutName);
	while(nTimeout > 0 && !result)
	{
#if _WIN32
		Sleep(500);
#else
		usleep(500000);
#endif
		nTimeout -= 500;
		result = init("127.0.0.1", 7777, nInterfaceFlags, wszSutName);
	}
	return result;
}

int openDefaultTriTciChannel(int nInterfaceFlags, wchar_t * wszSutName)
{
	return init("127.0.0.1", 7777, nInterfaceFlags, wszSutName);
}

int openTriTciChannel(char * pszAddr, int nPort, int nInterfaceFlags, 
	wchar_t * wszSutName)
{	
	return init(pszAddr, nPort, nInterfaceFlags, wszSutName);
}

int openTriTciChannelTimeout(char * pszAddr, int nPort, int nInterfaceFlags, 
	wchar_t * wszSutName, unsigned int nTimeout)
{	
	int result = init(pszAddr, nPort, nInterfaceFlags, wszSutName);
	while(nTimeout > 0 && !result)
	{
#ifdef _WIN32
		Sleep(500);
#else
		usleep(500000);
#endif
		nTimeout -= 500;
		result = init(pszAddr, nPort, nInterfaceFlags, wszSutName);
	}
	return result;
}

void closeTriChannel()
{
	closeLocalSocket();
#ifdef _WIN32
	CloseHandle(evSent);
#endif
}

static const TriAddress emptyAddress = {0, 0, 0};

void triEnqueueMessage (const TriPortId * tsiPortId,
		const TriAddress * sutAddress, const TriComponentId * componentId,
		const TriMessage * receivedMessage)
{
	int nLen;
	char * pData;
	int nOffset = 0;

	if (!sutAddress)
		sutAddress = &emptyAddress;

	// calculate length
	nLen = calcPortLen(tsiPortId) + calcBinLen(sutAddress, -1) + calcCompLen(componentId) +
		calcBinLen(receivedMessage, -1);
	pData = (char*)malloc(nLen);

	nOffset = encodePortId(tsiPortId, pData, nOffset);
	nOffset = encodeBinData(sutAddress, pData, nOffset, -1);
	nOffset = encodeCompId(componentId, pData, nOffset);
	nOffset = encodeBinData(receivedMessage, pData, nOffset, -1);
	sendMessage(EnqueueMsgCode, nLen, pData);
	free(pData);
}

void triEnqueueCall (const TriPortId * tsiPortId,
		const TriAddress * sutAddress, const TriComponentId * componentId,
		const TriSignatureId * signatureId, const TriParameterList * parameterList)
{
	int nLen = 0;
	char * pData;
	char ** pNames;
	int nOffset = 0;

	if (!sutAddress)
		sutAddress = &emptyAddress;
	// calculate length
	if(parameterList)
		nLen = parameterList->length;
	pNames = (char**)malloc(sizeof(char *) * nLen);
	memset(pNames, 0, sizeof(char *) * nLen);

	nLen = calcCompLen(componentId) + calcPortLen(tsiPortId) + calcBinLen(sutAddress, -1) +
		+ calcQualifiedName(signatureId) + calcParamListLen(parameterList, (const char***)&pNames);
	
	pData = (char*)malloc(nLen);
	nOffset = encodeCompId(componentId, pData, nOffset);
	nOffset = encodePortId(tsiPortId, pData, nOffset);
	nOffset = encodeBinData(sutAddress, pData, nOffset, -1);	
	nOffset = encodeQualifiedName(signatureId, pData, nOffset);
	nOffset = encodeParamList(parameterList, (const char ***)&pNames, pData, nOffset);
	free(pNames);
	sendMessage(EnqueueCallMsgCode, nLen, pData);
}

void triEnqueueReply (const TriPortId * tsiPortId,
		const TriAddress * sutAddress, const TriComponentId * componentId,
		const TriSignatureId * signatureId, const TriParameterList * parameterList,
		const TriParameter * returnValue)
{
	TriParameter emptyParam;
	int nLen;
	char * pData;
	int nOffset;
	char **pNames;
	if (!returnValue)
	{
		memset(&emptyParam, 0, sizeof(TriParameter));
		returnValue = &emptyParam;
	}
	if (!sutAddress)
		sutAddress = &emptyAddress;	// calculate length
	if(parameterList)
		nLen = parameterList->length;
	pNames = (char**)malloc(sizeof(char*) * nLen);
	memset(pNames, 0, sizeof(char*) * nLen);

	nLen = calcCompLen(componentId) + calcPortLen(tsiPortId) + calcBinLen(sutAddress, -1) +
		calcQualifiedName(signatureId) + calcParamListLen(parameterList, (const char ***)&pNames) + calcParamLen(returnValue, 0);

	pData = (char*)malloc(nLen);
	nOffset = 0;
	nOffset = encodeCompId(componentId, pData, nOffset);
	nOffset = encodePortId(tsiPortId, pData, nOffset);
	nOffset = encodeBinData(sutAddress, pData, nOffset, -1);
	nOffset = encodeQualifiedName(signatureId, pData, nOffset);
	nOffset = encodeParamList(parameterList, (const char ***)&pNames, pData, nOffset);
	nOffset = encodeParam(returnValue, 0, pData, nOffset);
	free(pNames);
	sendMessage(EnqueueReplyMsgCode, nLen, pData);
}

void triEnqueueException (const TriPortId * tsiPortId,
		const TriAddress * sutAddress, const TriComponentId * componentId,
		const TriSignatureId * signatureId, const TriException * exception)
{
	int nLen;
	char * pData;
	int nOffset = 0;

	if (!sutAddress)
		sutAddress = &emptyAddress;
	// calculate length
	nLen = calcCompLen(componentId) + calcPortLen(tsiPortId) + calcBinLen(sutAddress, -1) + 
		calcQualifiedName(signatureId) + calcBinLen(exception, -1);
	pData = (char*)malloc(nLen);
	nOffset = encodeCompId(componentId, pData, nOffset);
	nOffset = encodePortId(tsiPortId, pData, nOffset);
	nOffset = encodeBinData(sutAddress, pData, nOffset, -1);	
	nOffset = encodeQualifiedName(signatureId, pData, nOffset);
	nOffset = encodeBinData(exception, pData, nOffset, -1);
	sendMessage(EnqueueExceptionMsgCode, nLen, pData);
}

void triTimeout (const TriTimerId * timerId)
{
	// calculate length
	int nLen = calcBinLen(timerId, 0);
	char * pData = (char*)malloc(nLen);
	int nOffset = 0;
	nOffset = encodeBinData(timerId, pData, nOffset, 0);
	sendMessage(TimerTimeoutMsgCode, nLen, pData);
	free(pData);
}

////TciTM implementation
void tciRootModule(String moduleId)
{
	AbstractTriAckMessage * msg = 0;
	int nLen = HEADER_V3_LENGTH + calcStrLen(moduleId);
	char * pData = (char*)malloc(nLen);

	encodeString(moduleId, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(RootModuleMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

TciModuleIdListType tciGetImportedModules()
{
	char* pData = malloc(HEADER_V3_LENGTH);
	AbstractTriAckMessage * msg = 0;
	TciModuleIdListType idList;//TEMP
	
	msg = sendMessageWithAck(GetImportedModulesMsgCode, HEADER_V3_LENGTH, pData, GetImportedModulesReplyMsgCode);
	free(pData);

	idList.length = 0;
	idList.idList = 0;
	
	if(msg)
		decodeTciModuleIdList(&idList, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	
	return idList;
}

TciModuleParameterListType tciGetModuleParameters(TciModuleIdType moduleName)
{
	AbstractTriAckMessage * msg = 0;
	TciModuleParameterListType parList;//TEMP
	int nLen = HEADER_V3_LENGTH;
	int nOffset = ACK_HEADER_V3_LENGTH;
	char * pData;
	String pStr = 0;
	pStr = moduleName.moduleName;
	if(!pStr)
		pStr = moduleName.objectName;
	nLen += calcStrLen(pStr);
	pData = malloc(nLen);
	encodeString(pStr, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetModuleParametersMsgCode, nLen, pData, GetModuleParametersReplyMsgCode);
	free(pData);

	parList.length = 0;
	parList.modParList = 0;
	
	if(msg && msg->pData[nOffset++])
		nOffset = decodeTciModuleParameterList(&parList, msg->pData, msg->nLen, nOffset);
	disposeAbstractMsg(msg);

	return parList;
}

TciTestCaseIdListType tciGetTestCases()
{
	char * pData = malloc(HEADER_V3_LENGTH);
	AbstractTriAckMessage * msg = 0;
	TciTestCaseIdListType idList;//TEMP

	msg = sendMessageWithAck(GetTestCasesMsgCode, HEADER_V3_LENGTH, pData, GetTestCasesReplyMsgCode);
	free(pData);

	idList.length = 0;
	idList.idList = 0;
	
	if(msg)
		decodeTestCaseIdList(&idList, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	
	return idList;
}

TciParameterTypeListType tciGetTestCaseParameters (TciTestCaseIdType testCaseId)
{
	AbstractTriAckMessage * msg = 0;
	int nLen = HEADER_V3_LENGTH + calcQualifiedName(&testCaseId);
	char * pData = (char*)malloc(nLen);
	TciParameterTypeListType parList;//TEMP

	encodeQualifiedName(&testCaseId, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetTestCaseParametersMsgCode, nLen, pData, GetTestCaseParamReplyMsgCode);
	free(pData);
	parList.length = 0;
	parList.parList = 0;

	if(msg)
		decodeTciParameterTypeList(&parList, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	
	return parList;
}

TriPortIdList tciGetTestCaseTSI (TciTestCaseIdType testCaseId)
{
	AbstractTriAckMessage * msg = 0;
	int nLen = HEADER_V3_LENGTH + calcQualifiedName(&testCaseId);
	char * pData = (char*)malloc(nLen);
	TriPortIdList idList;//TEMP

	encodeQualifiedName(&testCaseId, pData, HEADER_V3_LENGTH);

	msg = sendMessageWithAck(GetTestCaseTsiMsgCode, nLen, pData, GetTestCaseTsiReplyMsgCode);
	free(pData);
	
	idList.length = 0;
	idList.portIdList = 0;

	if(msg && msg->pData[ACK_HEADER_V3_LENGTH])
		decodePortList(&idList, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH + 1);
	disposeAbstractMsg(msg);

	return idList;
}
void tciStartTestCase (TciTestCaseIdType testCaseId, TciParameterListType parameterlist)
{
	AbstractTriAckMessage * msg = 0;
	int nOffset, nLen = HEADER_V3_LENGTH + calcQualifiedName(&testCaseId) + calcTciParamListLen(&parameterlist);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeQualifiedName(&testCaseId, pData, HEADER_V3_LENGTH);
	nOffset = encodeTciParamList(&parameterlist, pData, nOffset);
	msg = sendMessageWithAck(StartTestCaseMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void tciStopTestCase()
{
	AbstractTriAckMessage * msg = 0;
	char* pData = (char*)malloc(HEADER_V3_LENGTH);
	msg = sendMessageWithAck(StopTestCaseMsgCode, HEADER_V3_LENGTH, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
TriComponentId tciStartControl()
{
	AbstractTriAckMessage * msg = 0;
	TriComponentId staticComponentId;
	char * pData = (char*)malloc(HEADER_V3_LENGTH);

	msg = sendMessageWithAck(StartControlMsgCode, HEADER_V3_LENGTH, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);

	staticComponentId.compInst.aux = 0;
	staticComponentId.compInst.bits = 8;
	staticComponentId.compInst.data = (unsigned char*)malloc(1);
	memset(staticComponentId.compInst.data, '0', 1);
	staticComponentId.compName = (char*)malloc(8);
	memcpy(staticComponentId.compName, "control", 8);
	staticComponentId.compType.aux = 0;
	staticComponentId.compType.moduleName = 0;
	staticComponentId.compType.objectName = 0;

	return staticComponentId;
}
void tciStopControl()
{
	AbstractTriAckMessage * msg = 0;
	char * pData = (char*)malloc(HEADER_V3_LENGTH);
	msg = sendMessageWithAck(StopControlMsgCode, HEADER_V3_LENGTH, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void setTciTMTestCaseStartedCallback(FTciTMTestCaseStarted pCallback)
{
	pTciTMTCStartedCallback = pCallback;
}
void setTciTMTestCaseTerminatedCallback(FTciTMTestCaseTerminated pCallback)
{
	pTciTMTCTerminatedCallback = pCallback;
}
void setTciTMGetModuleParCallback(FTciTMGetModulePar pCallback)
{
	pTciTMGetModParCallback = pCallback;
}
void setTciTMControlTerminatedCallback(FTciTMControlTerminated pCallback)
{
	pTciTMCtrlTerminatedCallback = pCallback;
}
void setTciTMLogCallback(FTciTMLog pCallback)
{
	pTciTMLogCallback = pCallback;
}
void setTciTMErrorCallback(FTciTMError pCallback)
{
	pTciTMErrorCallback = pCallback;
}
//SystemInterface
void siWriteToTCLog(const wchar_t * message)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + 4 + (int)wcslen(message) * 2;
	char* pData;

	pData = (char*)malloc(nLen);
	nOffset = encodeUString(message, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(SIwriteToTCLogMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
BinaryString siInternalEncode(const Value value)
{
	/*
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(value);
	char* pData;

	pData = (char*)malloc(nLen);
	nOffset = encodeTciValue(value, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(EncodeMsgCode, nLen, pData, TriMessageReplyMsgCode);
	free(pData);
	return decodeBinaryStringReply(msg);*/
	BinaryString bs;
	bs.aux = 0;
	bs.bits = 0;
	bs.data = 0;
	return bs;
}
Value siInternalDecode(const BinaryString *pBS, const Type decodingHypothesis)
{
	/*AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcBinLen(pBS, -1) + calcTciTypeLen(decodingHypothesis) + sizeof(int32_t), nBitOffset;
	char* pData;

	pData = (char*)malloc(nLen);
	nOffset = encodeBinData(pBS, pData, HEADER_V3_LENGTH, -1);
	nBitOffset = getBinaryStringStartingPosition(pBS);
	memcpy(&pData[nOffset], &nBitOffset, sizeof(int32_t)); 
	nOffset += sizeof(int32_t);
	nOffset = encodeTciType(decodingHypothesis, pData, nOffset);
	msg = sendMessageWithAck(DecodeMsgCode, nLen, pData, ValueReplyMsgCode);
	free(pData);
	return decodeValueReplyWithBitPosition(msg, (BinaryString *)pBS);*/
	return 0;
}
////////////////////////TCI Value + TCI Type
///////////////////////////////////////Type
TciModuleIdType tciGetDefiningModule(Type inst)
{
	TciModuleIdType type;
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetDefiningModuleMsgCode, nLen, pData, GetDefiningModuleReplyMsgCode);
	free(pData);
	decodeQualifiedName(&type, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	return type;
}

String tciGetName(Type inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);
	String pStr;

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetTypeNameMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	decodeString(&pStr, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	return pStr;
}

TciTypeClass tciGetTypeClass(Type inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);
	TciTypeClass typeCls;

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetTypeClassMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	decodeTciTypeClass(&typeCls, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	return typeCls;
}
Value tciNewInstance(Type inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(NewInstanceMsgCode, nLen, pData, ValueReplyMsgCode);
	free(pData);
	return decodeValueReply(msg);
}
String tciGetTypeEncoding(Type inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetTypeEncodingMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}
String* getTypeExtension(Type inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);
	String  *paStr;

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetTypeExtensionMsgCode, nLen, pData, GetTypeExtensionReplyMsgCode);
	free(pData);
	decodeTciExtension(&paStr, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	disposeAbstractMsg(msg);
	return paStr;
}
String tciGetTypeEncodingVariant(Type inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciTypeLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetTypeVariantMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}

///////////////////////////////////////Value
String tciGetValueEncoding(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetValueEncodingMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}

String tciGetValueEncodingVariant(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetValueVariantMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}

Type tciGetType(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetValueTypeMsgCode, nLen, pData, TypeReplyMsgCode);
	free(pData);
	return decodeTypeReply(msg);
}

Boolean tciNotPresent(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetNotPresentMsgCode, nLen, pData, BoolReplyMsgCode);
	free(pData);
	return decodeBoolReply(msg);
}
void tciSetNull(Value inst)
{
	memset(inst, 0, TCI_VALUE_LENGTH);
}

Boolean tciIsNull(Value inst)
{
	int * pInt = inst;
	if(!pInt)
		return 0xFF;
	if(*pInt != 0)
		return 0x00;
	pInt++;
	if(*pInt != 0)
		return 0x00;
	return 0xFF;
}

///////////////////////////////////////IntegerValue
String tciGetIntAbs(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetAbsIntegerValueMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}

unsigned long int tciIntGetNumberOfDigits(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetIntegerLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}

Boolean tciGetIntSign(Value inst)
{//true if number is positive, false otherwise
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetIntegerSignMsgCode, nLen, pData, BoolReplyMsgCode);
	free(pData);
	return decodeBoolReply(msg);
}

char tciGetIntDigit(Value inst, unsigned long int position)
{
	AbstractTriAckMessage *msg;
	int nOffset;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);
	char retCh = 0x00;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetDigitAtMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	if(ACK_HEADER_V3_LENGTH < nLen)
		retCh = msg->pData[ACK_HEADER_V3_LENGTH];
	disposeAbstractMsg(msg);
	return retCh;
}

void tciSetIntAbs(Value inst, String value)
{
	AbstractTriAckMessage *msg;
	int nOffset;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(value, pData, nOffset);

	msg = sendMessageWithAck(SetIntegerStringMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void tciSetNumberOfDigits(Value inst, unsigned long int dig_num)
{
	AbstractTriAckMessage *msg;
	int nOffset;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &dig_num, 4);

	msg = sendMessageWithAck(SetIntegerLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetIntSign(Value inst, Boolean sign)
{
	AbstractTriAckMessage *msg;
	int nOffset;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	pData[nOffset] = sign;

	msg = sendMessageWithAck(SetIntegerSignMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetIntDigit(Value inst, unsigned long int position, char digit)
{
	AbstractTriAckMessage *msg;
	int nOffset;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	nOffset += 4;
	pData[nOffset] = digit;

	msg = sendMessageWithAck(SetDigitAtMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////FloatValue
double tciGetFloatValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetFloatValueMsgCode, nLen, pData, DoubleReplyMsgCode);
	free(pData);
	return decodeDoubleReply(msg);
}
void tciSetFloatValue(Value inst, double value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + sizeof(double);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeDouble(&value, pData, nOffset);
	msg = sendMessageWithAck(SetFloatValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////BooleanValue
Boolean tciGetBooleanValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetBoolValueMsgCode, nLen, pData, BoolReplyMsgCode);
	free(pData);
	return decodeBoolReply(msg);
}

void tciSetBooleanValue(Value inst, Boolean value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeBoolean(value, pData, nOffset);
	msg = sendMessageWithAck(SetBoolValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////ObjidValue

TciObjidValue tciGetTciObjidValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetObjidValueMsgCode, nLen, pData, ObjidReplyMsgCode);
	free(pData);
	return decodeObjectidReply(msg);
}

void tciSetObjidValue(Value inst, TciObjidValue value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcObjidLen(&value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeObjectidValue(&value, pData, nOffset);
	msg = sendMessageWithAck(SetObjidValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
///////////////////////////////////////CharstringValue

TciCharStringValue tciGetCStringValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);
	TciCharStringValue val;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetCStringValueMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	decodeInt(&nLen, msg->pData, msg->nLen, ACK_HEADER_V3_LENGTH);
	msg->nLen = nLen;
	val.string = decodeSimpleStringReply(msg);
	return val;
}

unsigned long int tciGetCStringLength (Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetCStringLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}
char tciGetCStringCharValue(Value inst, long int position)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);
	char ret = 0x00;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetCharAtMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	if(msg->nLen >ACK_HEADER_V3_LENGTH)
		ret = msg->pData[ACK_HEADER_V3_LENGTH];
	disposeAbstractMsg(msg);
	return ret;
}

void tciSetCStringCharValue(Value inst, long int position, char value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	pData[nOffset + 4] = value;
	msg = sendMessageWithAck(SetCharAtMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void tciSetCStringValue(Value inst, TciCharStringValue value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + value.length;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &value.length, 4);
	nOffset += 4;
	memcpy(&pData[nOffset], value.string, value.length);
	msg = sendMessageWithAck(SetCStringValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetCStringLength(Value inst, unsigned long int len)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &len, 4);
	msg = sendMessageWithAck(SetCStringLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////UniversalCharstring
//methods
//get
TciUCStringValue tciGetUCStringValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetUStringBufferMsgCode, nLen, pData, UStringBufferReplyMsgCode);
	free(pData);
	return decodeUStringBufferReply(msg);
}
unsigned long int tciGetUCStringLength(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetUStringLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}
wchar_t tciGetUCStringCharValue(Value inst, unsigned long int position/*, TciUCValue result*/)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);
	wchar_t ret;
	int32_t nChar;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetUCharAtMsgCode, nLen, pData, UIntReplyMsgCode);
	free(pData);
	memcpy(&nChar, &msg->pData[ACK_HEADER_V3_LENGTH], 4);
	ret = (wchar_t)nChar;
	disposeAbstractMsg(msg);
	return ret;
}
//set
void tciSetUCStringCharValue(Value inst, unsigned long int position, wchar_t/*TciUCValue*/ value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + 4;
	int32_t nChar;
	char* pData = (char*)malloc(nLen);
	
	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	nOffset += 4;
	nChar = (int32_t)value; // convert to 32-bit
	memcpy(&pData[nOffset], &nChar, 4);

	msg = sendMessageWithAck(SetUCharAtMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetUCStringValue(Value inst, TciUCStringValue value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcUCStringBufferLen(&value);//calcUCStringLen(&value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	encodeUCStringBuffer(&value, pData, nLen, nOffset);
	msg = sendMessageWithAck(SetUStringBufferMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void tciSetUCStringLength(Value inst, unsigned long int len)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &len, 4);
	msg = sendMessageWithAck(SetUStringLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////BitstringValue
//methods
//get
String tciGetBStringValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetBStringValueMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}
unsigned long int tciGetBStringLength(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetBStringLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}
int tciGetBStringBitValue(Value inst, long int position)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);
	int ret = 0;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetBitAtMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	if(msg->nLen  > ACK_HEADER_V3_LENGTH)
		ret = msg->pData[ACK_HEADER_V3_LENGTH];
	disposeAbstractMsg(msg);
	return ret;
}
//set
void tciSetBStringBitValue(Value inst, unsigned long int position, int value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	nOffset += 4;
	pData[nOffset] = (char)value;
	msg = sendMessageWithAck(SetBitAtMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetBStringValue(Value inst, String value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(value, pData, nOffset);
	msg = sendMessageWithAck(SetBStringValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetBStringLength(Value inst,long int len)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &len, 4);
	msg = sendMessageWithAck(SetBStringLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////HexstringValue
//methods
//get
String tciGetHStringValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetHStringValueMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}
long int tciGetHStringLength(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetHStringLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}
int tciGetHStringHexValue(Value inst, unsigned long int position)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);
	char ret = 0x00;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetHexAtMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	if(msg->nLen >ACK_HEADER_V3_LENGTH)
		ret = msg->pData[ACK_HEADER_V3_LENGTH];
	disposeAbstractMsg(msg);
	return ret;
}
//set
void tciSetHStringHexValue(Value inst, unsigned long int position, int value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	nOffset += 4;
	pData[nOffset] = (char)value;
	msg = sendMessageWithAck(SetHexAtMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetHStringValue(Value inst, String value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(value, pData, nOffset);
	msg = sendMessageWithAck(SetHStringValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetHStringLength(Value inst, unsigned long int len)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &len, 4);
	msg = sendMessageWithAck(SetHStringLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////OctetstringValue
//methods
//get
String tciGetOStringValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetOStringValueMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}
unsigned long int tciGetOStringLength(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetOStringLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}
int tciGetOStringOctetValue(Value inst, unsigned long int position)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);
	int ret = 0;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetOctetAtMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	
	if(msg->nLen > ACK_HEADER_V3_LENGTH)
		ret = msg->pData[ACK_HEADER_V3_LENGTH];
	ret &= 0x000000FF;
	disposeAbstractMsg(msg);
	return ret;
}
//set
void tciSetOStringOctetValue(Value inst, unsigned long int position, int value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	nOffset += 4;
	pData[nOffset] = (char)value;
	msg = sendMessageWithAck(SetOctetAtMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetOStringValue(Value inst, String value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(value, pData, nOffset);
	msg = sendMessageWithAck(SetOStringValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
void tciSetOStringLength(Value inst, unsigned long int len)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &len, 4);
	msg = sendMessageWithAck(SetOStringLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////RecordValue
//methods
//
Value tciGetRecFieldValue(Value inst, String fieldName)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(fieldName);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(fieldName, pData, nOffset);
	msg = sendMessageWithAck(GetRecordItemValueMsgCode, nLen, pData, ValueReplyMsgCode);
	free(pData);
	return decodeValueReply(msg);
}

void tciSetRecFieldValue(Value inst, String fieldName, Value value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(fieldName) + calcTciValueLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(fieldName, pData, nOffset);
	nOffset = encodeTciValue(value, pData, nOffset);
	msg = sendMessageWithAck(SetRecordItemValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

char** tciGetRecFieldNames(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetRecordFieldNamesMsgCode, nLen, pData, StringArrayReplyMsgCode);
	free(pData);
	return decodeStringArrayReply(msg);
}
void setFieldOmitted(Value inst, String fieldName)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(fieldName);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(fieldName, pData, nOffset);
	msg = sendMessageWithAck(SetFieldOmittedMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////RecordOfValue
//methods
//get
Type tciGetRecOfElementType(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetRecordOfElementTypeMsgCode, nLen, pData, TypeReplyMsgCode);
	free(pData);
	return decodeTypeReply(msg);
}

Value tciGetRecOfFieldValue(Value inst, unsigned long int position)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &position, 4);
	msg = sendMessageWithAck(GetRecordOfItemMsgCode, nLen, pData, ValueReplyMsgCode);
	free(pData);
	return decodeValueReply(msg);
}

unsigned long int tciGetRecOfLength(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetRecordOfLengthMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}

//set
void tciAppendRecOfFieldValue(Value inst, Value value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcTciValueLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeTciValue(value, pData, nOffset);
	msg = sendMessageWithAck(AppendRecordOfItemMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void tciSetRecOfFieldValue(Value inst, unsigned long int position, Value value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4 + calcTciValueLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeTciValue(value, pData, nOffset);
	memcpy(&pData[nOffset], &position, 4);
	//nOffset += 4;
	
	msg = sendMessageWithAck(SetRecordOfItemMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void tciSetRecOfLength(Value inst, unsigned long int len)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &len, 4);
	nOffset += 4;
	
	msg = sendMessageWithAck(SetRecordOfLengthMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////UnionValue
//methods
//
Value tciGetUnionVariant(Value inst, String variantName)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(variantName);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(variantName, pData, nOffset);
	msg = sendMessageWithAck(GetUnionItemValueMsgCode, nLen, pData, ValueReplyMsgCode);
	free(pData);
	return decodeValueReply(msg);
}
void tciSetUnionVariant(Value inst, String variantName, Value value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(variantName) + calcTciValueLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(variantName, pData, nOffset);
	nOffset = encodeTciValue(value, pData, nOffset);
	msg = sendMessageWithAck(SetUnionItemValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
String tciGetUnionPresentVariantName(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(PresentVariantNameMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}
char** tciGetUnionVariantNames(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetVariantNamesMsgCode, nLen, pData, StringArrayReplyMsgCode);
	free(pData);
	return decodeStringArrayReply(msg);
}

///////////////////////////////////////EnumeratedValue
//methods
//
String tciGetEnumValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetEnumValueMsgCode, nLen, pData, SimpleStringReplyMsgCode);
	free(pData);
	return decodeSimpleStringReply(msg);
}
void tciSetEnumValue(Value inst, String enumValue)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + calcStrLen(enumValue);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeString(enumValue, pData, nOffset);
	msg = sendMessageWithAck(SetEnumValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

unsigned long tciGetEnumInt(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetEnumIntValueMsgCode, nLen, pData, NumericReplyMsgCode);
	free(pData);
	return decodeNumericReply(msg);
}
void tciSetEnumInt(Value inst, unsigned long intValue)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], &intValue, 4);
	msg = sendMessageWithAck(SetEnumIntValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////VerdictValue
//methods
//
int tciGetVerdictValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);
	int ret = 0;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetVerdictValueMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	ret = msg->pData[ACK_HEADER_V3_LENGTH];
	disposeAbstractMsg(msg);
	return ret;
}

void tciSetVerdictValue(Value inst, int verdict)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	pData[nOffset] = (unsigned char)verdict;
	msg = sendMessageWithAck(SetVerdictValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////AddressValue
//methods
//Implemented through Union
Value tciGetAddressValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetAddressValueMsgCode, nLen, pData, ValueReplyMsgCode);
	free(pData);
	return decodeValueReply(msg);
}

void tciSetAddressValue(Value inst, Value value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst)+ calcTciValueLen(value);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	nOffset = encodeTciValue(value, pData, nOffset);
	msg = sendMessageWithAck(SetAddressValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}
///////////////////////////////////////CharValue
//methods
//
char tciGetCharValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);
	char ret = 0x00;

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetCharValueMsgCode, nLen, pData, ByteReplyMsgCode);
	free(pData);
	if(msg->nLen > ACK_HEADER_V3_LENGTH)
		ret = msg->pData[ACK_HEADER_V3_LENGTH];
	disposeAbstractMsg(msg);
	return ret;
}
void tciSetCharValue(Value inst, char value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 1;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	pData[nOffset] = value;
	msg = sendMessageWithAck(SetCharValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

///////////////////////////////////////UniversalCharValue
//methods
//
void tciGetUCharValue(Value inst, TciUCValueOld value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst);
	char* pData = (char*)malloc(nLen);
	
	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	
	msg = sendMessageWithAck(GetUCharValueMsgCode, nLen, pData, UIntReplyMsgCode);
	free(pData);
	memcpy(value, &msg->pData[ACK_HEADER_V3_LENGTH], 4);
	disposeAbstractMsg(msg);
}

void tciSetUCharValue(Value inst, TciUCValueOld value)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcTciValueLen(inst) + 4;
	char* pData = (char*)malloc(nLen);

	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	memcpy(&pData[nOffset], value, 4);
	msg = sendMessageWithAck(SetUCharValueMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

Type tciGetTypeForName(const char * typeName)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcStrLen(typeName);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeString(typeName, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(GetNamedTypeMsgCode, nLen, pData, TypeReplyMsgCode);
	free(pData);
	return decodeTypeReply(msg);
}

Type tciGetIntegerType(void)
{
	return tciGetTypeForName("integer");
}

Type tciGetFloatType(void)
{
	return tciGetTypeForName("float");
}

Type tciGetBooleanType(void)
{
	return tciGetTypeForName("boolean");
}

Type tciGetCharType(void)
{
	return tciGetTypeForName("char");
}

Type tciGetUniversalCharType(void)
{
	return tciGetTypeForName("universal char");
}

Type tciGetTciObjidType(void)
{
	return tciGetTypeForName("objid");
}

Type tciGetTciCharstringType(void)
{
	return tciGetTypeForName("charstring");
}

Type tciGetUniversalCharstringType(void)
{
	return tciGetTypeForName("universal charstring");
}

Type tciGetHexstringType(void)
{
	return tciGetTypeForName("hexstring");
}

Type tciGetBitstringType(void)
{
	return tciGetTypeForName("bitstring");
}

Type tciGetOctetstringType(void)
{
	return tciGetTypeForName("octetstring");
}

Type tciGetVerdictType(void)
{
	return tciGetTypeForName("verdicttype");
}

void tciErrorReq(const char * message)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + calcStrLen(message);
	char* pData = (char*)malloc(nLen);

	nOffset = encodeString(message, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(TciErrorReqMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	disposeAbstractMsg(msg);
}

void disposeTciType(Type inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + TCI_TYPE_LENGTH;
	char* pData;

	if(!inst)
		return;
	pData = (char*)malloc(nLen);
	nOffset = encodeTciType(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(UnregisterTciObjectMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	free(inst);
	disposeAbstractMsg(msg);
}

void disposeTciValue(Value inst)
{
	AbstractTriAckMessage *msg;
	int nOffset, nLen = HEADER_V3_LENGTH + TCI_VALUE_LENGTH;
	char* pData;

	if(!inst)
		return;
	pData = (char*)malloc(nLen);
	nOffset = encodeTciValue(inst, pData, HEADER_V3_LENGTH);
	msg = sendMessageWithAck(UnregisterTciObjectMsgCode, nLen, pData, AckMsgCode);
	free(pData);
	free(inst);
	disposeAbstractMsg(msg);
}
