#ifndef TCI_CD_C
#define TCI_CD_C

//#define NULL 0;
#include <stdlib.h>
#include <string.h>
#include "TciCD.h"
#include "Shared/TciC.h"
#include "Shared/TciCallbacks.h"

#if _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __attribute__((visibility("default")))
#endif

const char * MEMORY_EXCEPTION = "Memory allocation failed";
const char * INDEX_EXCEPTION = "Index out of range";
const char * VALUE_FORMAT_EXCEPTION = "Invalid value format";
const char * VALUE_RANGE_EXCEPTION = "Value out allowed range";
const char * UNKNOWN_TYPE_EXCEPTION = "Unknown type";

extern TCallbacks callbacks;

void tciErrorReq(const char * message)
{
	(callbacks.fTciErrorReq)(message);
}

/////////////////////////////////////// Type ///////////////////////

Type tciGetTypeForName(const char * typeName)
{
	return (callbacks.fTciGetTypeForName)(typeName);
}
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");
}

DLL_EXPORT Value Decode(BinaryString * msg, Type type)
{
	return tciDecode(*msg, type);
}

unsigned char * copyBits(BinaryString src)
{
	unsigned char * dst;
	unsigned long len;
	long roundVal = src.bits;
	while(roundVal % 8)
		roundVal++;
	len = roundVal / 8;
	dst = (unsigned char*)malloc(len);
	if(!dst)
		return 0;
	memcpy(dst, src.data, len);
	return dst;
}

DLL_EXPORT BinaryString * Encode(Value value)
{
	BinaryString * bs, retBS;

	retBS = tciEncode(value);

	bs = (BinaryString*)malloc(sizeof(BinaryString));
	if(!bs)
		return 0;
	bs->aux = 0;
	bs->bits = retBS.bits;
	bs->data = copyBits(retBS);
	clearBinaryString(&retBS);
	return bs;
}

DLL_EXPORT void ReleaseBinaryString(BinaryString* val)
{
	if(val)
	{
		free(val->aux);
		val->aux = 0;
		free(val->data);
		val->data = 0;
		val->bits = 0;
	}
	free(val);

}

#endif
