/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Guru Nagarajan, Intel - Initial re-implementation of Agent Controller
 *    IBM - native2unicode conversion functions from RAComm.c.
 *
 * $Id: TPTPString.c,v 1.10 2009/09/03 01:12:07 jcayne Exp $
 *******************************************************************************/
#ifndef _WIN32
 #include <langinfo.h>
 #include <locale.h>
 #include <iconv.h>
 #include <string.h>
 #include <strings.h>
#endif


#include "tptp/TPTPUtils.h"
#include "tptp/TPTPCommon.h" /*must follow TPTPUtils.h or get winsock conflicts */
#include <stdarg.h>

void tptp_strcopy(tptp_string* destination, const tptp_string* source)
{
/*
	destination->bufsize=source->bufsize;
	destination->data=(char *)tptp_malloc(sizeof(char)*source->bufsize+1);
	if(source->data)
	{
		memcpy(destination->data, source->data, source->bufsize);
	}
	destination->data[source->bufsize]='\0';
*/
}

void tptp_strcreate(tptp_string* newString, const char* stringBuffer)
{
	/*
	if(stringBuffer)
	{
		newString->bufsize=strlen(stringBuffer);
		newString->data=(char*)tptp_malloc(newString->bufsize+1);
		strcpy(newString->data, stringBuffer);
	}
	else
	{
		newString->bufsize=0;
		newString->data=NULL;
	}
	*/
}

void tptp_strconcat(tptp_string* destString, tptp_string* srcString)
{
	/*
	if(srcString->bufsize > 0)
	{
		strcat(destString->data, srcString->data);
		destString->bufsize = strlen(destString->data);
	}
	*/
}

void tptp_strdestroy(tptp_string* tptpstring)
{
	/*
	 if(tptpstring->bufsize > 0)
	 {
		tptp_free(tptpstring->data);
		tptpstring->data = NULL;
		tptpstring->bufsize = 0;
	 }
	 */
}

tptp_int32 tptp_strlen(const tptp_string* source)
{
	/*return source->bufsize;*/
	return 0;
}


tptp_int32 tptp_strcmp(const tptp_string* string1,const tptp_string* string2)
{
	tptp_int32 ret = 1;
	/*
	if(string1 && string2)
	{
		if(string1->bufsize != string2->bufsize) return ret;
		if(string1->bufsize == string2->bufsize)
		{
			return strcmp(string1->data, string2->data);
		}
	}
	*/
	return ret;

}

/*****************************************************************
 * The native2unicode() and unicode2native() platform independent
 * functions and their accompanying implementation have been copied
 * here from the IBM implementation in RAComm.c.
 ******************************************************************/
/*
 * Returns the number of multi-byte char in the converted buffer
 * Arg 0: Pointer to the destination storage of the multi-byte buffer
 * Arg 1: Pointer to the source storage of the multi-byte buffer
 * Arg 2: Number of multi-byte in the buffer
 */
size_t native2unicode(char** out, char* in, size_t size_in) {
#if defined(_WIN32)
	int count;
	wchar_t* temp;

	count = mb2wc(&temp, in, size_in, GetACP());
	count = wc2mb(out, temp, count, CP_UTF8);
	tptp_free(temp);

	return count;
#elif defined(__OS400__)
	/* UTF-8  is IBMCCSID0120800000000000000000000 */
	/* Native is IBMCCSID0000000000000000000000000 */
	return convert(out, in, size_in, "IBMCCSID0120800000000000000000000", "IBMCCSID0000000000000000000000000");
#elif defined(_HPUX)
	return convert(out, in, size_in, "utf8", nl_langinfo(CODESET)); /* HP-UX iconv_open() cannot take "UTF-8" */
#else
	return convert(out, in, size_in, "UTF-8", nl_langinfo(CODESET));
#endif
}

/*
 * Returns the number of multi-byte char in the converted buffer
 * Arg 0: Pointer to the destination storage of the multi-byte buffer
 * Arg 1: Pointer to the source storage of the multi-byte buffer
 * Arg 2: Number of multi-byte in the buffer
 */
size_t unicode2native(char** out, char* in, size_t size_in) {
	int count;
#if defined(_WIN32)
	wchar_t* temp;

	count = mb2wc(&temp, in, size_in, CP_UTF8);
	count = wc2mb(out, temp, count, GetACP());
	tptp_free(temp);
#elif defined(__OS400__)
	/* UTF-8  is IBMCCSID0120800000000000000000000 */
	/* Native is IBMCCSID0000000000000000000000000 */
	return convert(out, in, size_in, "IBMCCSID0000000000000000000000000", "IBMCCSID0120800000000000000000000");
#elif defined(_HPUX)
	return convert(out, in, size_in, nl_langinfo(CODESET), "utf8"); /* HP-UX iconv_open() cannot take "UTF-8" */
#else
	return convert(out, in, size_in, nl_langinfo(CODESET), "UTF-8");
#endif

	return count;
}

/*
 * -----------------------------------------------------------------------------
 * WIN32 conversion functions
 * -----------------------------------------------------------------------------
 */
#ifdef _WIN32
/*
 * Returns the number of wchar
 * Arg 0: Pointer to the destination storage of the wchar buffer
 * Arg 1: Pointer to the source storage of the multi-byte char buffer
 * Arg 2: Number of wchar in the wchar buffer
 * Arg 3: Codepage for the conversion
 *
 */
int mb2wc(wchar_t** lpWideCharStr, char* lpMultiByteStr, int cbMultiByte, int cp) {
	int cchWideChar;

	/*
	 * Calculate the number of wchar required for the buffer
	 */
	cchWideChar = MultiByteToWideChar(
		cp,
		0,
		(LPSTR)lpMultiByteStr,
		cbMultiByte,
		NULL,
		0);

	*lpWideCharStr = (wchar_t*)tptp_malloc(sizeof(wchar_t) * cchWideChar + 1);
	BZERO(*lpWideCharStr, sizeof(wchar_t) * cchWideChar + 1);

	return MultiByteToWideChar(
		cp,
		0,
		(LPSTR)lpMultiByteStr,
		cbMultiByte,
		*lpWideCharStr,
		cchWideChar);
}

/*
 * Returns the number of multi-byte char
 * Arg 0: Pointer to the destination storage of the multi-byte buffer
 * Arg 1: Pointer to the source storage of the wchar buffer
 * Arg 2: Number of multi-byte in the multi-byte buffer
 * Arg 3: Codepage for the conversion
 *
 */
int wc2mb(char** lpMultiByteStr, wchar_t* lpWideCharStr, int cchWideChar, int cp) {
	int cbMultiByte;

	/*
	 * Calculate the number of multibyte required for the buffer
	 */
	cbMultiByte = WideCharToMultiByte(
		cp,
		0,
		lpWideCharStr,
		cchWideChar,
		NULL,
		0,
		NULL,
		NULL);

	*lpMultiByteStr = (char*)tptp_malloc(sizeof(char) * cbMultiByte + 1);
	BZERO(*lpMultiByteStr, sizeof(char) * cbMultiByte + 1);

	return WideCharToMultiByte(
		cp,
		0,
		lpWideCharStr,
		cchWideChar,
		(LPSTR)(*lpMultiByteStr),
		cbMultiByte,
		NULL,
		NULL);
}
#else
int convert(char** out, char* in, size_t size_in, char* to_cp, char* from_cp) {
	iconv_t cd; /* code page converter */
	char* inBuf_copy = 0; /* a copy of the input buffer, so that the original value is not modified */
	char* inBuf_start = 0; /* a pointer to the beginning of the inBuf_copy buffer used for free() */
	char* tempBuf = 0; /* a temporary buffer used to store the output of the conversion, allocated larger than required */
	char* tempBuf_start = 0; /* a pointer to the beginning of the tempBuf buffer used for free() */
	size_t outLen; /* length of the allocated output buffer */
	size_t convLen; /* return value from iconv() */
	size_t tempLen; /* length of the allocated output buffer, will actually be the numnber of bytes left in the buffer */
	size_t inLen_copy; /* a copy of the length of the input buffer */
#if _DEBUG
	int i;
#endif

	setlocale(LC_CTYPE, "");
	cd = iconv_open(to_cp, from_cp); /* to, from */
#if _DEBUG
		printf("DEBUG: CP(%s) -> CP(%s)\n", from_cp, to_cp);
#endif

#if defined(__OS400__)
	if(cd.return_value == -1) { /* iconv_t under OS/400 is a structure */
#else
	if(cd == (iconv_t)-1) {
#endif
#if _DEBUG
		printf("DEBUG: Error calling iconv_open()\n");
#endif
		*out = 0; /* Bug 80588 */
		return 0;
	}

	inLen_copy = size_in; /* make a copy of the length */
	inBuf_copy = (char*)tptp_malloc(sizeof(char) * inLen_copy); /* make a copy of the input buffer */
	memcpy(inBuf_copy, in, size_in);
	inBuf_start = inBuf_copy; /* mark the start of the input buffer */
#if _DEBUG
	printf("DEBUG: inLen_copy = %d\n", inLen_copy);
	printf("DEBUG: inBuf_copy = ");
	for(i = 0; i < inLen_copy; i++) {
		printf("%c", inBuf_copy[i]);
	}
	printf("\n");
#endif

	tempLen = inLen_copy * 2; /* create the output buffer, larger than expected since we don't know the actual size yet */
	outLen = tempLen; /* bytes left and buffer size are the same at this point */
	tempBuf = (char*)tptp_malloc(sizeof(char) * tempLen);
	tempBuf_start = tempBuf; /* mark the beginning of the output buffer */
	convLen = iconv(cd, &inBuf_copy, &inLen_copy, &tempBuf, &tempLen); /* perform the conversion */
	if(convLen == -1) {
#if _DEBUG
		printf("DEBUG: Error running iconv(), errno = %d\n", errno);
		switch(errno) {
			case EILSEQ:
				printf("DEBUG: Invalid byte sequence at byte %d\n", inBuf_copy - inBuf_start);
				break;
			case E2BIG:
				printf("DEBUG: Ran out of space in the output buffer\n");
				break;
			case EINVAL:
				printf("DEBUG: Incomplete byte sequence at the end of the input buffer\n");
				break;
		}
#endif
		*out = 0; /* Bug 80588 */
		return 0; /* return 0 if it fails */
	}
#if _DEBUG
	printf("DEBUG: Bytes left(tempLen) = %d\n", tempLen);
	printf("DEBUG: Output buffer(tempBuf_start) = ");
	for(i = 0; i < outLen - tempLen; i++) {
		printf("%c", tempBuf_start[i]);
	}
	printf("\n");
#endif

	*out = (char*)tptp_malloc(sizeof(char) * (outLen - tempLen + 1)); /* create the output buffer with the actual size, adding a null */
	BZERO(*out, outLen - tempLen + 1);
	memcpy(*out, tempBuf_start, outLen - tempLen);  /* copy the contents from the temp buffer */
#if _DEBUG
	printf("DEBUG: Copied buffer(out)\n");
	printf("DEBUG: Output buffer size = %d\n", outLen - tempLen);
#endif

	iconv_close(cd);

	tptp_free(inBuf_start); /* free up working buffers */
	tptp_free(tempBuf_start);

	return (outLen - tempLen);
}
#endif /* _WIN32 */
