/****************************************************************
 *								*
 * Copyright (c) 2012-2021 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#include "mdef.h"

#include "gtm_string.h"

#include "gtm_caseconv.h"
#include "gtm_utf8.h"
#include "gtm_conv.h"

GBLREF UConverter	*chset_desc[CHSET_MAX_IDX];
GBLREF casemap_t	casemaps[MAX_CASE_IDX];
GBLREF u_casemap_t	gtm_strToTitle_ptr;		/* Function pointer for gtm_strToTitle */

LITREF mstr		chset_names[CHSET_MAX_IDX_ALL];

/* Note these routines are separated from gtm_conv.c to avoid pulling into gtmsecshr all the stuff the conversion modules use */

error_def(ERR_ICUERROR);

/* Startup initializations of conversion data */
void gtm_conv_init(void)
{
	assert(gtm_utf8_mode);
	/* Implicitly created CHSET descriptor for UTF-8 */
	get_chset_desc(&chset_names[CHSET_UTF8]);
	assert(NULL != chset_desc[CHSET_UTF8]);
	/* initialize the case conversion disposal functions */
	casemaps[0].u = u_strToUpper;
	casemaps[1].u = u_strToLower;
	casemaps[2].u = gtm_strToTitle_ptr;
}

UConverter* get_chset_desc(const mstr* chset)
{
	int 			chset_indx;
	UErrorCode		status;

	if ((0 >= (chset_indx = verify_chset(chset))) || (CHSET_MAX_IDX <= chset_indx))
		return NULL;
	if (NULL == chset_desc[chset_indx])
	{
		status = U_ZERO_ERROR;
		chset_desc[chset_indx] = ucnv_open(chset_names[chset_indx].addr, &status);
		if (U_FAILURE(status))
			RTS_ERROR_ABT(VARLSTCNT(3) ERR_ICUERROR, 1, status);	/* strange and unexpected ICU unhappiness */
		/* Initialize the callback for illegal/invalid characters, so that conversion
		 * stops at the first illegal character rather than continuing with replacement */
		status = U_ZERO_ERROR;
		ucnv_setToUCallBack(chset_desc[chset_indx], &callback_stop, NULL, NULL, NULL, &status);
		if (U_FAILURE(status))
			RTS_ERROR_ABT(VARLSTCNT(3) ERR_ICUERROR, 1, status);	/* strange and unexpected ICU unhappiness */
	}
	return chset_desc[chset_indx];
}

/* Routine to verify given parameter against supported CHSETs.
 * Valid arguments (case-insensitive):
 *	"M", "UTF-8", "UTF-16", "UTF-16LE" and "UTF-16BE"
 * Returns
 *	-1 (if invalid argument) or
 *	0  (if "M") or
 *	non-zero index to an entry of chset_names[] (if valid)
 */
int verify_chset(const mstr *parm)
{
	const mstr	*vptr, *vptr_top;
	char		mode[MAX_CHSET_LEN];

	if ((MIN_CHSET_LEN > parm->len) || (MAX_CHSET_LEN < parm->len))
		return -1; /* Parameter is smaller or larger than any possible CHSET */
	/* Make a translated copy of the parm */
	lower_to_upper((unsigned char *)mode, (unsigned char *)parm->addr, parm->len);
	/* See if any of our possibilities match */
	for (vptr = chset_names, vptr_top = vptr + CHSET_MAX_IDX_ALL; vptr < vptr_top; ++vptr)
	{
		if (parm->len == vptr->len &&
		    0 == memcmp(mode, vptr->addr, vptr->len))
			return (int)(vptr - chset_names); /* return the index */
	}
	return -1;
}

void callback_stop(const void* context, UConverterToUnicodeArgs *args, const char *codeUnits,
		int32_t length, UConverterCallbackReason reason, UErrorCode *pErrorCode)
{
	/* EMPTY BODY:
	 * By not resetting the pErrorCode, this routine returns to ICU routine directing
	 * it to stop and return immediately
	 */
}
