#ifndef TCI_DATA_C
#define TCI_DATA_C

#include <stdlib.h>
#include <string.h>
#include "TciData.h"
#include "TciCallbacks.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

extern TCallbacks callbacks;
extern FTciSetNull fnSetNull;
extern FTciIsNull fnIsNull;
extern FTciGetRecordOfOffset fnGetRecordOfOffset;
extern FTciIsOmit fnIsOmit;
extern FTciIsAny fnIsAny;
extern FTciIsAnyOrOmit fnIsAnyOrOmit;
extern FTciGetTemplateDef fnGetTemplateDef;
extern FTciIsAnyNonValue fnIsAnyNonValue;
extern FTciIsAllNonValue fnIsAllNonValue;
extern FTciGetTemplateDefNonValue fnGetTemplateDefNonValue;
extern FTciGetValueListSize fnGetValueListSize;
extern FTciIsValueListEmpty fnIsValueListEmpty;
extern FTciGetValueListItem fnGetValueListItem;
extern FTciGetUCStringValueWchar fnGetUCStringValueWchar;
extern FTciSetUCStringValueWchar fnSetUCStringValueWchar;
extern FTciSIWriteToTCLog fnSIWriteToTCLog;
extern FTciSIInternalDecode fnSIInternalDecode;
extern FTciSIInternalEncode fnSIInternalEncode;
extern FTciReleaseBinaryStringManaged fnReleaseBinaryStringManaged;
extern FTciGetUCStringValueWchar fnGetUCStringValueWchar32;
extern FTciSetUCStringValueWchar fnSetUCStringValueWchar32;
extern FTciGetEnumInt fnGetEnumInt;
extern FTciSetEnumInt fnSetEnumInt;

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;

void siWriteToTCLog(const wchar_t * message)
{
	if(message && fnSIWriteToTCLog)
		fnSIWriteToTCLog(message);
}

Value siInternalDecode(const BinaryString * pBS, const Type decodingHypothesis)
{
	if(fnSIInternalDecode)
		return fnSIInternalDecode(pBS, decodingHypothesis);
	return NULL;
}

BinaryString siInternalEncode(const Value inst)
{
	BinaryString bs;
	if(fnSIInternalEncode)
	{
		int nLen;
		BinaryString * tmp = fnSIInternalEncode(inst);
		bs.aux = tmp->aux;
		bs.bits = tmp->bits;
		nLen = tmp->bits;
		while(nLen%8)
			nLen++;
		nLen = nLen/8;
		bs.data = (unsigned char*)malloc(nLen);
		memcpy(bs.data, tmp->data, nLen);
		if(fnReleaseBinaryStringManaged)
			fnReleaseBinaryStringManaged(tmp);
	}
	else
		memset(&bs, 0, sizeof(BinaryString));
	return bs;
}

TciModuleIdType tciGetDefiningModule(Type inst)
{
	return (callbacks.fGetDefiningModule)(inst);
}
String tciGetName(Type inst)
{
	return (callbacks.fGetName)(inst);
}
TciTypeClass tciGetTypeClass(Type inst)
{
	int nCls = (callbacks.fGetTypeClass)(inst);
	if(nCls == 0)//Address,
		return TCI_ADDRESS_TYPE;
	else if(nCls == 1)// Anytype,
		return TCI_ANYTYPE_TYPE;
	else if(nCls == 2)// Bitstring,
		return TCI_BITSTRING_TYPE;
	else if(nCls == 3)// BooleanType,
		return TCI_BOOLEAN_TYPE;
	else if(nCls == 4)// CharType,
		return TCI_CHAR_TYPE;
	else if(nCls == 5)// Charstring,
		return TCI_CHARSTRING_TYPE;
	else if(nCls == 6)// Component,
		return TCI_COMPONENT_TYPE;
	else if(nCls == 7)// Enumerated,
		return TCI_ENUMERATED_TYPE;
	else if(nCls == 8)// Float,
		return TCI_FLOAT_TYPE;
	else if(nCls == 9)// Hexstring,
		return TCI_HEXSTRING_TYPE;
	else if(nCls == 10)// IntegerType,
		return TCI_INTEGER_TYPE;
	else if(nCls == 11)// Objid,
		return TCI_OBJID_TYPE;
	else if(nCls == 12)// Octetstring,
		return TCI_OCTETSTRING_TYPE;
	else if(nCls == 13)// Record,
		return TCI_RECORD_TYPE;
	else if(nCls == 14)// RecordOf,
		return TCI_RECORD_OF_TYPE;
	else if(nCls == 15)// SetType,
		return TCI_SET_TYPE;
	else if(nCls == 16)// SetOf,
		return TCI_SET_OF_TYPE;
	else if(nCls == 17)// Union,
		return TCI_UNION_TYPE;
	else if(nCls == 18)// UniversalChar,
		return TCI_UNIVERSAL_CHAR_TYPE;
	else if(nCls == 19)// UniversalCharstring,
		return TCI_UNIVERSAL_CHARSTRING_TYPE;
	else if(nCls == 20)// Verdict,
		return TCI_VERDICT_TYPE;
	else //if(nCls == 21)// Array
		return TCI_ARRAY_TYPE;
}
Value tciNewInstance(Type inst)
{
	return (callbacks.fNewInstance)(inst);
}
String tciGetTypeEncoding(Type inst)
{
	return (callbacks.fGetTypeEncoding)(inst);
}
String* getTypeExtension(Type inst)
{
	return (callbacks.fGetTypeExtension)(inst);
}
String tciGetTypeEncodingVariant(Type inst)
{
	return (callbacks.fGetTypeEncodingVariant)(inst);
}

/////////////////////////////////////// Value ///////////////////////

String tciGetValueEncoding(Value inst)
{
	return (callbacks.fGetValueEncoding)(inst);
}
String tciGetValueEncodingVariant(Value inst)
{
	return (callbacks.fGetValueEncodingVariant)(inst);
}
Type tciGetType(Value inst)
{
	return (callbacks.fGetType)(inst);
}
Boolean tciNotPresent(Value inst)
{
	return (callbacks.fNotPresent)(inst);
}
void tciSetNull(Value inst)
{
	if (fnSetNull)
		fnSetNull(inst);
}
Boolean tciIsNull(Value inst)
{
	return fnIsNull ? fnIsNull(inst) : 0x00;
}

///////////////////////////////////////INTEGER///////////////////////
String tciGetIntAbs(Value inst)
{
	return (callbacks.fGetIntAbs)(inst);
}
unsigned long int tciIntGetNumberOfDigits(Value inst)
{
	return (long int)(callbacks.fIntGetNumberOfDigits)(inst);	
}
Boolean tciGetIntSign(Value inst)
{
	return (callbacks.fGetIntSign)(inst);
}
char tciGetIntDigit(Value inst, unsigned long int position)
{
	return (callbacks.fGetIntDigit)(inst, (int32_t)position);
}
void tciSetIntAbs(Value inst, String value)
{
	(callbacks.fSetIntAbs)(inst, value);
}
void tciSetNumberOfDigits(Value inst, unsigned long int dig_num)
{
	(callbacks.fSetNumberOfDigits)(inst, dig_num);
}
void tciSetIntSign(Value inst, Boolean sign)
{
	(callbacks.fSetIntSign)(inst, sign);
}
void tciSetIntDigit(Value inst, unsigned long int position, char digit)
{
	(callbacks.fSetIntDigit)(inst, (int32_t)position, digit);
}

//////////////////////////////////////FLOAT///////////////
double tciGetFloatValue(Value inst)
{
	return (callbacks.fGetFloatValue)(inst);
}
void tciSetFloatValue(Value inst, double value)
{
	(callbacks.fSetFloatValue)(inst, value);
}

//////////////////////////////////////BOOL////////////////
Boolean tciGetBooleanValue(Value inst)
{
	return (callbacks.fGetBooleanValue)(inst);
}
void tciSetBooleanValue(Value inst, Boolean value)
{
	(callbacks.fSetBooleanValue)(inst, value);
}

/////////////////////////////////OBJID////////////////////////////////
TciObjidValue tciGetTciObjidValue(Value inst)
{
	TciObjidValue res;
	TciObjidValue32 tmp = (callbacks.fGetObjidValue)(inst);
	res.length = (unsigned long)tmp.length;
	res.elements = tmp.elements;
	return res;
}

void tciSetObjidValue(Value inst, TciObjidValue value)
{
	TciObjidValue32 tmp;
	tmp.length = (int32_t)value.length;
	tmp.elements = value.elements;
	(callbacks.fSetObjidValue)(inst, tmp);
}

/////////////////////////////////////CHARSTRING//////////////////////////
TciCharStringValue tciGetCStringValue(Value inst)
{
	TciCharStringValue res;
	TciCharStringValue32 tmp = (callbacks.fGetCStringValue)(inst);
	res.length = (unsigned long)tmp.length;
	res.string = tmp.string;
	return res;
}
void tciSetCStringValue(Value inst, TciCharStringValue value)
{
	TciCharStringValue32 tmp;
	tmp.length = (int32_t)value.length;
	tmp.string = value.string;
	(callbacks.fSetCStringValue)(inst, tmp);
}
char tciGetCStringCharValue(Value inst, long int position)
{
	return (callbacks.fGetCStringCharValue)(inst, (int32_t)position);
}
void tciSetCStringCharValue(Value inst, long int position, char value)
{
	(callbacks.fSetCStringCharValue)(inst, (int32_t)position, value);
}
unsigned long int tciGetCStringLength (Value inst)
{
	return (long int)(callbacks.fGetCStringLength)(inst);
}
void tciSetCStringLength(Value inst, unsigned long int len)
{
	(callbacks.fSetCStringLength)(inst, (int32_t)len);
}

//////////////////////////////////BITSTRING////////////////
String tciGetBStringValue(Value inst)
{
	return (callbacks.fGetBStringValue)(inst);
}
void tciSetBStringValue(Value inst, String value)
{
	(callbacks.fSetBStringValue)(inst, value);
}
int tciGetBStringBitValue(Value inst, long int position)
{
	return (int)(callbacks.fGetBStringBitValue)(inst, (int32_t)position);
}
void tciSetBStringBitValue(Value inst, unsigned long int position, int value)
{
	(callbacks.fSetBStringBitValue)(inst, (int32_t)position, (int32_t)value);
}
unsigned long int tciGetBStringLength(Value inst)
{
	return (long int)(callbacks.fGetBStringLength)(inst);
}
void tciSetBStringLength(Value inst, long int len)
{
	(callbacks.fSetBStringLength)(inst, (int32_t)len);
}

//////////////////////////////////HEXSTRING////////////////
String tciGetHStringValue(Value inst)
{
	return (callbacks.fGetHStringValue)(inst);
}
void tciSetHStringValue(Value inst, String value)
{
	(callbacks.fSetHStringValue)(inst, value);
}
int tciGetHStringHexValue(Value inst, unsigned long int position)
{
	return (int)(callbacks.fGetHStringHexValue)(inst, (int32_t)position);
}
void tciSetHStringHexValue(Value inst, unsigned long int position, int value)
{
	(callbacks.fSetHStringHexValue)(inst, (int32_t)position, (int32_t)value);
}
long int tciGetHStringLength(Value inst)
{
	return (long int)(callbacks.fGetHStringLength)(inst);
}
void tciSetHStringLength(Value inst, unsigned long int len)
{
	(callbacks.fSetHStringLength)(inst, (int32_t)len);
}

/////////////////////////////////////OCTETSTRING////////////////////

String tciGetOStringValue(Value inst)
{
	return (callbacks.fGetOStringValue)(inst);
}
void tciSetOStringValue(Value inst, String value)
{
	(callbacks.fSetOStringValue)(inst, value);
}
int tciGetOStringOctetValue(Value inst, unsigned long int position)
{
	return (callbacks.fGetOStringOctetValue)(inst, (int32_t)position);
}
void tciSetOStringOctetValue(Value inst, unsigned long int position, int value)
{
	(callbacks.fSetOStringOctetValue)(inst, (int32_t)position, (int32_t)value);
}
unsigned long int tciGetOStringLength(Value inst)
{
	return (long int)(callbacks.fGetOStringLength)(inst);
}
void tciSetOStringLength(Value inst, unsigned long int len)
{
	(callbacks.fSetOStringLength)(inst, (int32_t)len);
}

/////////////////////////////////////RECORD//////////////////////////
Value tciGetRecFieldValue(Value inst, String fieldName)
{
	return (callbacks.fGetRecFieldValue)(inst, fieldName);
}
void tciSetRecFieldValue(Value inst, String fieldName, Value val)
{
	(callbacks.fSetRecFieldValue)(inst, fieldName, val);
}
char** tciGetRecFieldNames(Value inst)
{
	return (callbacks.fGetRecFieldNames)(inst);
}
void setFieldOmitted(Value inst, String fieldName)
{
	(callbacks.fSetFieldOmitted)(inst, fieldName);
}

/////////////////////////////////////RECORD_OF_VALUE/////////////////////////
Value tciGetRecOfFieldValue(Value inst, unsigned long int position)
{
	return (callbacks.fGetRecOfFieldValue)(inst, (int32_t)position);
}
void tciSetRecOfFieldValue(Value inst, unsigned long int position, Value value)
{
	(callbacks.fSetRecOfFieldValue)(inst, (int32_t)position, value);
}
void tciAppendRecOfFieldValue(Value inst, Value value)
{
	(callbacks.fAppendRecOfFieldValue)(inst, value);
}
Type tciGetRecOfElementType(Value inst)
{
	return (callbacks.fGetRecOfElementType)(inst);
}
unsigned long int tciGetRecOfLength(Value inst)
{
	return (long int)(callbacks.fGetRecOfLength)(inst);
}
void tciSetRecOfLength(Value inst, unsigned long int len)
{
	(callbacks.fSetRecOfLength)(inst, (int32_t)len);
}
unsigned long int tciGetOffset(Value inst)
{
	return fnGetRecordOfOffset ? fnGetRecordOfOffset(inst) : 0;
}
//////////////////////////////////////UNION///////////////
Value tciGetUnionVariant(Value inst, String variantName)
{
	return (callbacks.fGetUnionVariant)(inst, variantName);
}
void tciSetUnionVariant(Value inst, String variantName, Value value)
{
	(callbacks.fSetUnionVariant)(inst, variantName, value);
}
String tciGetUnionPresentVariantName(Value inst)
{
	return (callbacks.fGetUnionPresentVariantName)(inst);
}
char** tciGetUnionVariantNames(Value inst)
{
	return (callbacks.fGetUnionVariantNames)(inst);
}

//////////////////////////////////////ENUM////////////////
String tciGetEnumValue(Value inst)
{
	return (callbacks.fGetEnumValue)(inst);
}
void tciSetEnumValue(Value inst, String enumValue)
{
	(callbacks.fSetEnumValue)(inst, enumValue);
}

unsigned long tciGetEnumInt(Value inst)
{
	return fnGetEnumInt ? (fnGetEnumInt)(inst) : 0;
}
void tciSetEnumInt(Value inst, unsigned long intValue)
{
	if(fnSetEnumInt)
		fnSetEnumInt(inst, intValue);
}

//////////////////////////////////////VERDICT/////////////
int tciGetVerdictValue(Value inst)
{
	return (int32_t)(callbacks.fGetVerdictValue)(inst);
}
void tciSetVerdictValue(Value inst, int verdict)
{
	(callbacks.fSetVerdictValue)(inst, (int32_t)verdict);
}

//////////////////////////////////////ADDRESS/////////////
Value tciGetAddressValue(Value inst)
{
	return (callbacks.fGetAddressValue)(inst);
}
void tciSetAddressValue(Value inst, Value value)
{
	(callbacks.fSetAddressValue)(inst, value);
}

//////////////////////////////////CHAR///////////////////////////////////////
char tciGetCharValue(Value inst)
{
	return (callbacks.fGetCharValue)(inst);
}
void tciSetCharValue(Value inst, char value)
{
	(callbacks.fSetCharValue)(inst, value);
}

/////////////////UNIVERSAL_CHAR///////////////////////////////////////
void tciGetUCharValue(Value inst, TciUCValueOld value)
{
	(callbacks.fGetUCharValue)(inst, value);
}
void tciSetUCharValue(Value inst, TciUCValueOld value)
{
	(callbacks.fSetUCharValue)(inst, value);
}

//////////////////////////////////UNIVERSAL_STRING///////////////////////////
TciUCStringValue tciGetUCStringValue(Value inst)
{
	return (fnGetUCStringValueWchar)(inst);
}

unsigned long int tciGetUCStringLength(Value inst)
{
	return (callbacks.fGetUCStringLength)(inst);
}

int32_t _byteswap_ulong(int32_t nSrc)
{
	int32_t nDst = 0;
	int i;
	for(i = 0; i < 4; i++)
	{
		nDst |= (nSrc & 0x000000FF);
		nDst = nDst<<8;
		nSrc = nSrc>>8;
	}
	return nDst;
}

wchar_t tciGetUCStringCharValue(Value inst, unsigned long int position)
{
	TciUCValueOld oldChar;
#ifdef _WIN32
	unsigned long nChar;
#else
	int32_t nChar;
#endif
	(callbacks.fGetUCStringCharValue)(inst, position, oldChar);
	memcpy(&nChar, &oldChar, 4);
#ifdef _WIN32
	nChar = _byteswap_ulong(nChar);
#else
	nChar = __builtin_bswap32(nChar);
#endif
	return (wchar_t)nChar;
}

void tciSetUCStringCharValue(Value inst, unsigned long int position, wchar_t value)
{
	//(callbacks.fSetUCStringCharValue)(inst, position, value);//(version < TCI 4.2.2)
	TciUCValueOld tmp;
	//swap to big endian
#ifdef _WIN32
	unsigned long nChar = (unsigned long)value;
	nChar = _byteswap_ulong(nChar);
#else
	int32_t nChar = (int32_t)value;
	nChar = __builtin_bswap32(nChar);
#endif
	memcpy(&tmp, &nChar, 4);
	(callbacks.fGetUCStringCharValue)(inst, position, tmp);
}

void tciSetUCStringValue(Value inst, TciUCStringValue value)
{
	(fnSetUCStringValueWchar)(inst, value);
}

void tciSetUCStringLength(Value inst, unsigned long int len)
{
	(callbacks.fSetUCStringLength)(inst, len);
}
//////////////////////////////////VALUE TEMPLATE///////////////////////////
Boolean tciIsOmit(TciValueTemplate inst)
{
	return fnIsOmit ? fnIsOmit(inst) : 0;
}
Boolean tciIsAny(TciValueTemplate inst)
{
	return fnIsAny ? fnIsAny(inst) : 0;
}
Boolean tciIsAnyOrOmit(TciValueTemplate inst)
{
	return fnIsAnyOrOmit ? fnIsAnyOrOmit(inst) : 0;
}
String tciGetTemplateDef(TciValueTemplate inst)
{
	return fnGetTemplateDef ? fnGetTemplateDef(inst) : 0;
}
//////////////////////////////////NON-VALUE TEMPLATE///////////////////////////
Boolean tciIsAnyNonValue(TciNonValueTemplate inst)
{
	return fnIsAnyNonValue ? fnIsAnyNonValue(inst) : 0;
}
Boolean tciIsAllNonValue(TciNonValueTemplate inst)
{
	return fnIsAllNonValue ? fnIsAllNonValue(inst) : 0;
}
String tciGetTemplateDefNonValue(TciNonValueTemplate inst)
{
	return fnGetTemplateDefNonValue ? fnGetTemplateDefNonValue(inst) : 0;
}
//////////////////////////////////VALUE LIST///////////////////////////
int tciGetValueListSize(TciValueList inst)
{
	return fnGetValueListSize ? fnGetValueListSize(inst) : -1;
}
Boolean tciIsValueListEmpty(TciValueList inst)
{
	return fnIsValueListEmpty ? fnIsValueListEmpty(inst) : 0xFF;
}
Value tciGetValueListItem(TciValueList inst, int index)
{
	return fnGetValueListItem ? fnGetValueListItem(inst, (int32_t)index) : 0;
}

#endif
