#include  <stdio.h>
#include  <string.h>
#include  <stdlib.h>
#include  "GeneType.h"
#include  "PyBasic.h"

JINT	GbkHzcodeToYjcode(JINT nHzcode);
JINT	HzcodeToYjcode(JINT nHzcode);
JINT	Hzcode2244ToYjcode(JINT nHzcode);
JINT	Hzcode2244ToYjSMcode(JINT nHzcode);
JINT	GetDyzInfo(JINT nHzcode, JINT* pnDyzYjCode);
JINT	EncodeDyzTo2244(JINT nHzcode, JINT nYjcode);
JINT	FastMatchYinJieStr(CHAR* szPystr);
UCHAR*	RecovDyz2244(UCHAR *szDyz2244);

CHAR	LastChar (JINT nYinjieCode);
CHAR	FirstChar(JINT nYinjieCode);
JINT	ValidButLastChar (JINT nYinjieCode);
JINT	ValidButFirstChar(JINT nYinjieCode);
JINT	ValidAddChar(CHAR ch, JINT nYinjieCode);

/*
**  nHzcode range: [0xB0A1 ~ 0xF7FE] || [0x2001 ~ 0x2244]
**		   [0x2001 ~ 0x2244] contains 580 DuoYinZi.
**  Lookup table GBHZCODETOYJ[] and DYZCODETOYJ[] to return
**  a integer Yinjie code 0~414.
*/
JINT HzcodeToYjcode(JINT nHzcode)
{
	JINT	hi, low;
	JINT	res;
	JINT	t1, t2, t3, t4;

	hi  = (nHzcode >> 8) & 0x00FF;
	low = nHzcode & 0x00FF;
	t1  = t2 = t3 = t4 = 0;

	res = 0xFFFF;

	if ((hi == 0xD7) && (low >= 0xFA) && (low <= 0xFE))
		res = 0xFFFF;
	else if ((hi >= 0xB0) && (hi <= 0xF7) && (low >= 0xA1) && (low <= 0xFE))
	{
		t1 = (hi - 0xB0) * 94 + (low - 0xA1) + 1;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (JINT)( (GBHZCODETOYJ[t2] >> (32 - t4)) & 0x01FF ) +
			      (JINT)( (GBHZCODETOYJ[t3] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (JINT)( GBHZCODETOYJ[t2] >> (32 - t4) ) & 0x01FF;
	}
	else if ((nHzcode >= 0x2001) && (nHzcode <= 0x2244))
	{
		t1 = nHzcode - 0x2000;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (JINT)( (DYZCODETOYJ[t2] >> (32 - t4)) & 0x01FF ) +
			      (JINT)( (DYZCODETOYJ[t3] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (JINT)( DYZCODETOYJ[t2] >> (32 - t4) ) & 0x01FF;
	}
	else
		res = 0xFFFF;

	return (res);
}


/*
**  nHzcode range: [0x8140 ~ 0xA0FE] || [0xAA40 ~ 0xFEFE] || [0x2001 ~ 0x2244]
**		   [0x2001 ~ 0x2244] contains 580 DuoYinZi.
**  Lookup table GBHZCODETOYJ[] and DYZCODETOYJ[] to return
**  a integer Yinjie code 0~414.
*/
JINT GbkHzcodeToYjcode(JINT nHzcode)
{
	JINT	hi, low;
	JINT	res;
	JINT	t1, t2, t3, t4;

	hi  = (nHzcode >> 8) & 0x00FF;
	low = nHzcode & 0x00FF;
	t1  = t2 = t3 = t4 = 0;

	res = 0xFFFF;
	if ((hi >= 0x81) && (hi <= 0xA0) && (low >= 0x40) && (low <= 0xFE))
	{
		t1 = (hi - 0x81) * 191 + (low - 0x40) + 1;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (JINT)( (GBKHZCODETOYJ[t2] >> (32 - t4)) & 0x01FF ) +
			      (JINT)( (GBKHZCODETOYJ[t3] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (JINT)( GBKHZCODETOYJ[t2] >> (32 - t4) ) & 0x01FF;
	}
	else if ((hi >= 0xAA) && (hi <= 0xFE) && (low >= 0x40) && (low <= 0xFE))
	{
		t1 = (hi - 0xAA) * 191 + (low - 0x40) + 1;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (JINT)( (GBKHZCODETOYJ[t2 + (9 * 191)] >> (32 - t4)) & 0x01FF ) +
			      (JINT)( (GBKHZCODETOYJ[t3 + (9 * 191)] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (JINT)( GBKHZCODETOYJ[t2 + (9 * 191)] >> (32 - t4) ) & 0x01FF;
	}
	else if ((nHzcode >= 0x2001) && (nHzcode <= 0x2244))
	{
		t1 = nHzcode - 0x2000;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (JINT)( (DYZCODETOYJ[t2] >> (32 - t4)) & 0x01FF ) +
			      (JINT)( (DYZCODETOYJ[t3] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (JINT)( DYZCODETOYJ[t2] >> (32 - t4) ) & 0x01FF;
	}
	else
		res = 0xFFFF;

	if (res == 0x01FF)
		res = 0xFFFF;

	return (res);
}


/*
**  Lookup the DYZLIST[580] to see if this nHzcode is a DuoYinZi.
**  index of DYZLIST by High Byte is placed in INDEXOFDYZLIST
**  return: JINT	   number of DuoYin, for example: 1, 2, 3  else, 0
**	    pnDyzYjCode	   yinjiecode include yinjie code
*/
JINT GetDyzInfo(JINT nHzcode, JINT* pnDyzYjCode)
{
	JINT	nHiHzPos, nLowHz;
	JINT	i, j;

	nHiHzPos = ((nHzcode & 0xFF00) >> 8) - 0xB0;
	nLowHz = nHzcode & 0x00FF;

	j = 0;
	for (i = INDEXOFDYZLIST[nHiHzPos]; i < INDEXOFDYZLIST[nHiHzPos + 1]; i++)
	{
		if( (DYZLIST[i] & 0x00FF) == nLowHz )
		{
			pnDyzYjCode[j] = DYZYJCODE[i];
			j++;
		}
	}

	return (j);
}


/*
**  nHzcode is Normal Hanzi Code defined in GB or GBK.
**  If nHzcode indicates a DYZ, return 0x2001 ~ (TOTAL_DYZYINJIE - 1 + 0x2001) [0x2001 + 0x2244]
**  Else, return 0xFFFF.
*/
JINT EncodeDyzTo2244(JINT nHzcode, JINT nYjcode)
{
	JINT	nHiHzPos, nLowHz;
	JINT	i;

	nHiHzPos = ((nHzcode & 0xFF00) >> 8) - 0xB0;
	if (nHiHzPos < 0)
		return (0xFFFF);
	nLowHz = nHzcode & 0x00FF;

	for (i = INDEXOFDYZLIST[nHiHzPos]; i < INDEXOFDYZLIST[nHiHzPos + 1]; i++)
	{
		if ( ((DYZLIST[i] & 0x00FF) == nLowHz) && (DYZYJCODE[i] == nYjcode) )
			return (i + 0x2001);
	}

	return (0xFFFF);
}


/*
**  Lookup the equal string of szPystr in YINJIESTR_CSZ[415].
**  If successfully, return 0~414; otherwise, return -1.
**  If chFirst is 'i' 'u' or 'v', return -1 directly.
*/
JINT FastMatchYinJieStr(CHAR* szPystr)
{
	JINT	i, j, nLen;
	CHAR	chFirst;
	JINT	nFromYJStr, nToYJStr, nShengmuIndex;

	i = 0;
	nLen = (JINT)strlen(szPystr);

	j = 0;
	if (nLen > 0)
	{
		chFirst = szPystr[0];

		if ((chFirst == 'i') || (chFirst == 'u') || (chFirst == 'v'))
			return (-1);

		nFromYJStr = INDEXSMTOYINJIE[ INDEXMAGIC[(JINT)(chFirst - 'a')] ];
		nToYJStr = INDEXSMTOYINJIE[ INDEXMAGIC[(JINT)(chFirst - 'a')] + 1];
		nShengmuIndex = INDEXMAGIC[(JINT)(chFirst - 'a')];

		if ((chFirst == 'c') && (nLen > 1) && (szPystr[1] == 'h'))
		{
			nFromYJStr = INDEXSMTOYINJIE[3];
			nToYJStr = INDEXSMTOYINJIE[4];
			nShengmuIndex = 3;
		}
		else if ((chFirst == 's') && (nLen > 1) && (szPystr[1] == 'h'))
		{
			nFromYJStr = INDEXSMTOYINJIE[19];
			nToYJStr = INDEXSMTOYINJIE[20];
			nShengmuIndex = 19;
		}
		else if ((chFirst == 'z') && (nLen > 1) && (szPystr[1] == 'h'))
		{
			nFromYJStr = INDEXSMTOYINJIE[25];
			nToYJStr = INDEXSMTOYINJIE[26];
			nShengmuIndex = 25;
		}

		i = nFromYJStr;
		do {
			j = strcmp (YINJIESTR_CSZ[i], szPystr);
			i++;
		} while ((i < nToYJStr) && (j != 0));
	}

	if (j == 0)
		return (i - 1);
	else
		return (-1);
}


/*
**  nYinjieCode Valid from 0 to 414. Return the last
**  character of this YinJie String.
*/
CHAR LastChar(JINT nYinjieCode)
{
	CHAR   res = ' ';		/* SPACE */
	JINT   i = 0;

	if ((nYinjieCode >= 0) && (nYinjieCode <= 414))
	{
		while (YINJIESTR_CSZ[nYinjieCode][i] != '\0')
			i++;
		res = YINJIESTR_CSZ[nYinjieCode][i-1];
	}
	return res;
}

/*
**  nYinjieCode Valid from 0 to 414
*/
CHAR FirstChar(JINT nYinjieCode)
{
	CHAR   res = ' ';		/* SPACE */

	if ((nYinjieCode >= 0) && (nYinjieCode <= 414))
		res = YINJIESTR_CSZ[nYinjieCode][0];
	return res;
}

/*
**  Valid but the end CHARacter?
**  return 0~414 if valid, else return 0xFFFF
*/
JINT ValidButLastChar(JINT nYinjieCode)
{
	JINT	i, nTmpRes;
	CHAR	szStr[7];

	for (i = 0; i < 7; i++)
		szStr[i] = '\0';

	if ((nYinjieCode >= 0) && (nYinjieCode <= 414))
	{
		i = 0;
		while (YINJIESTR_CSZ[nYinjieCode][i+1])
		{
			szStr[i] = YINJIESTR_CSZ[nYinjieCode][i];
			i++;
		}

		nTmpRes = FastMatchYinJieStr(szStr);
		if(nTmpRes != -1)
			return nTmpRes;
	}
	return 0xFFFF;
}


/*
** Valid add a new CHARacter before it?
** return 0~414 if valid, else return 0xFFFF
*/
JINT ValidAddChar(CHAR ch, JINT nYinjieCode)
{
	JINT	i, nTmpRes;
	CHAR	szStr[7];

	for (i = 0; i < 7; i++)
		szStr[i] = '\0';

	szStr[0] = ch;
	if ((nYinjieCode >= 0) && (nYinjieCode <= 414))
	{
		i = 0;
		while (YINJIESTR_CSZ[nYinjieCode][i])
		{
			szStr[i + 1] = YINJIESTR_CSZ[nYinjieCode][i];
			i++;
		}

		nTmpRes = FastMatchYinJieStr(szStr);
		if(nTmpRes != -1)
			return nTmpRes;
	}

	return 0xFFFF;
}


/*
**  Valid but first CHARacter ?
**  return 0~414 if valid, else return 0xFFFF
*/
JINT ValidButFirstChar(JINT nYinjieCode)
{
	JINT	i, nTmpRes;
	CHAR	szStr[7];

	for (i = 0; i < 7; i++)
		szStr[i] = '\0';

	if ((nYinjieCode >= 0) && (nYinjieCode <= 414))
	{
		i = 0;
		while (YINJIESTR_CSZ[nYinjieCode][i+1])
		{
			szStr[i] = YINJIESTR_CSZ[nYinjieCode][i+1];
			i++;
		}

		nTmpRes = FastMatchYinJieStr(szStr);
		if(nTmpRes != -1)
			return nTmpRes;
	}

	return 0xFFFF;
}


/*
**  Recover these Hanzi String which encode by GB&Dyz2244 to normal GB
**  Length of returned string is determined by the length of szDyz2244
**
**  This function must be rewritten to process failure of malloc()!!!
*/
UCHAR* RecovDyz2244(UCHAR *szDyz2244)
{
	JINT	i, j, nLen, nHlfLen;
	JINT	nDyzCode, nNormCode;
	static	UCHAR*	szNorm;			/* Used by function RecovDyz2244() */

	nLen = strlen((CHAR*)szDyz2244);
	nHlfLen = nLen / 2;

	if(szNorm != NULL)
		free(szNorm);

	szNorm = (UCHAR*)malloc(nLen + 2);
	if (szNorm == NULL)
	{
		fprintf(stderr, "Failed to alloc Memory in function ReconDyz2244\n");
		return szDyz2244;
	}

	for (i = 0; i < (nLen + 2); i++)
		szNorm[i] = '\0';

	j = 0;
	for (i = 0; i < nHlfLen; i++)
	{
		nDyzCode = szDyz2244[(2 * i) + 1] + ((JINT)szDyz2244[2 * i] << 8);
		if ((nDyzCode >= 0x2001) && (nDyzCode <= 0x2244))
		{
			nNormCode	  = DYZLIST[nDyzCode - 0x2001];
			szNorm[2 * i]	  = (UCHAR)((nNormCode & 0xFF00) >> 8);
			szNorm[2 * i + 1] = (UCHAR)(nNormCode & 0x00FF);
		}
		else
		{
			szNorm[2 * i]	   = szDyz2244[2 * i];
			szNorm[2 * i + 1]  = szDyz2244[2 * i + 1];
		}
	}

	return (szNorm);
}


/*
**  nHzcode range: [0xB0A1 ~ 0xF7FE] || [0x2001 ~ 0x2244]
**  [0x2001 ~ 0x2244] contains 580 DuoYinZi.
**  Lookup table GBHZCODETOYJ[] and DYZCODETOYJ[] to return
**  a integer Yinjie code 0~414.
*/
JINT Hzcode2244ToYjcode(JINT nHzcode)
{
	JINT	hi, low;
	JINT	res;
	JINT	t1, t2, t3, t4;

	hi = (nHzcode >> 8) & 0x00FF;
	low = nHzcode & 0x00FF;
	t1 = t2 = t3 = t4 = 0;
	res = 0xFFFF;

	if ((hi >= 0xB0) && (hi <= 0xF7) && (low >= 0xA1) && (low <= 0xFE))
	{
		t1 = (hi - 0xB0) * 94 + (low - 0xA1) + 1;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (int)( (GBHZCODETOYJ[t2] >> (32 - t4)) & 0x01FF ) +
			      (int)( (GBHZCODETOYJ[t3] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (int)( GBHZCODETOYJ[t2] >> (32 - t4) ) & 0x01FF;
	}
	else if ((nHzcode >= 0x2001) && (nHzcode <= 0x2244))
	{
		t1 = nHzcode - 0x2000;
		t2 = (t1 * 9 - 1) / 32;
		t3 = ((t1 - 1) * 9 - 1) / 32;
		t4 = (t1 * 9) % 32;

		if (t2 > t3)
			res = (int)( (DYZCODETOYJ[t2] >> (32 - t4)) & 0x01FF ) +
			      (int)( (DYZCODETOYJ[t3] << t4) & 0x01FF );
		else if (t2 == t3)
			res = (int)( DYZCODETOYJ[t2] >> (32 - t4) ) & 0x01FF;
	}
	else
		res = 0xFFFF;

	return (res);
}


/*
**  nHzcode range: [0xB0A1 ~ 0xF7FE] || [0x2001 ~ 0x2244]
**  [0x2001 ~ 0x2244] contains 580 DuoYinZi.
**
**  Return ShengMu YinjieCode(450~475) of this Hanzi. If unNormal, return 0xFFFF
*/
JINT Hzcode2244ToYjSMcode(JINT nHzcode)
{
	JINT	nTmpRes;
	JINT	nRet;

	nTmpRes = Hzcode2244ToYjcode(nHzcode);

	if (nTmpRes != 0xFFFF)
	{
		if ((nTmpRes >= 38) && (nTmpRes < 57 ))		/* "ch" */
			nRet =	3 + 450;
		else if ((nTmpRes >= 301) && (nTmpRes < 320))	/* "sh" */
			nRet = 19 + 450;
		else if ((nTmpRes >= 395) && (nTmpRes < 415))	/* "zh" */
			nRet = 25 + 450;
		else
			nRet = INDEXMAGIC[(JINT)(YINJIESTR_CSZ[nTmpRes][0] - 'a')] + 450;

		return nRet;
	}

	return 0xFFFF;
}

