#include  <stdio.h>
#include  <string.h>
#include  <stdlib.h>

#include  <sys/types.h>
#include  <sys/stat.h>
#include  <fcntl.h>

#include  "GeneType.h"
#include  "PyBasic.h"
#include  "ciku.h"

JINT    Hzcode2244ToYjSMcode(JINT nHzcode);
JINT    Hzcode2244ToYjcode(JINT nHzcode);
UCHAR*  RecovDyz2244(UCHAR *szDyz2244);
VOID    InitStructSc(SysCandi* psc);
JINT    EnumSysCandi(JINT* pnOrgYj, JINT nLenYj, SysCandi* psc, JINT* pnSize, JWORD* pwCandiBuf, JINT nMatchMode, JINT nMode);
SysCandi* LookupSysCiku(JINT *pnOrgYj, JINT nLenYj, JINT nMatchMode);
VOID    SortSysCandi(SysCandi* psc);

static  BYTE   *pCkAll;

/*
**  Read out all those data in System Ciku file to pCkAll.
*/
JINT GetCikuData(CHAR* szSysCikuName)
{
	FILE*   pfCiku;
	JINT    i, k;
	JINT    nFileSize;
	
	CikuHeader  *pCkh;
	ShIndex     *pShi;
	DhIndex     *pDhi;
	MhIndex     *pMhi;
	GbkIndex    *pGbki;
	BYTE        *pShArea;
	BYTE        *pDhArea;
	BYTE        *pMhArea;
	BYTE        *pGbkArea;
	
	pfCiku = fopen(szSysCikuName, "rb");
	if (pfCiku == NULL)
	{
		fprintf(stderr, "Failed to fopen() System Ciku File: %s\n", szSysCikuName);
		return FALSE;
	}
	
	pCkh = (CikuHeader*)malloc(sizeof(CikuHeader));
	if (pCkh == NULL)
	{
		fprintf(stderr, "Failed to malloc() for pCkh in GetCikuInfo.\n");	
		return FALSE;
	}
	
	fseek(pfCiku, 0, SEEK_SET);
	if (fread (pCkh, 1, sizeof(CikuHeader), pfCiku) != sizeof(CikuHeader) )
	{
		fprintf(stderr, "Failed to fread() System Ciku Header.\n");
		return FALSE;
	}
	
	/* Check Magic Word in Header */
	if ((pCkh->nMagicDescHi != 0x35303539) || (pCkh->nMagicDescLow != 0x34333442))
	{
		fprintf(stderr, "This is not the valid System Ciku Data File.\n");
		return FALSE;
	}
	nFileSize = pCkh->nFileSize;
	
	fseek(pfCiku, 0, SEEK_END);
	if (nFileSize != ftell(pfCiku))
	{
		fprintf(stderr, "System Ciku File was demaged.\n");
		return FALSE;
	}
	
	free(pCkh);
	pCkh = NULL;
	
	pCkAll = (BYTE*)malloc(nFileSize);
	if (pCkAll == NULL)
	{
		fprintf(stderr, "Failed to malloc() for pCkAll in GetCikuInfo.\n");
		return FALSE;
	}
	
	fseek(pfCiku, 0, SEEK_SET);
	if ((JINT)fread (pCkAll, 1, nFileSize, pfCiku) != nFileSize )
	{
		fprintf(stderr, "Failed to fread() System Ciku File.\n");
		return FALSE;
	}
	fclose(pfCiku);
	
	pCkh     = (CikuHeader *)pCkAll;
	pShi     = (ShIndex  *)(pCkAll + pCkh->nIdxShPos);
	pDhi     = (DhIndex  *)(pCkAll + pCkh->nIdxDhPos);
	pMhi     = (MhIndex  *)(pCkAll + pCkh->nIdxMhPos);
	pGbki    = (GbkIndex *)(pCkAll + pCkh->nIdxGbkPos);
	
	pShArea  = (BYTE *)(pCkAll + pShi->nStartPos);
	pDhArea  = (BYTE *)(pCkAll + pDhi->nStartPos);
	pMhArea  = (BYTE *)(pCkAll + pMhi->nStartPos);
	pGbkArea = (BYTE *)(pCkAll + pGbki->nStartPos);
	
	for(i = 0; i < NUM_YINJIE; i++)
		for(k = (pShi->nYjOff[i] & 0x00FFFFFF); k < (pShi->nYjOff[i + 1] & 0x00FFFFFF); k++)
			*(pShArea + k) ^= (BYTE)((i + 56) / 2);

	for(i = 0; i < NUM_YINJIE; i++)
		for(k = pDhi->nYjOff[i]; k < pDhi->nYjOff[i + 1]; k++)
			*(pDhArea + k) ^= (BYTE)((i + 56) / 2);

	for(i = 0; i < NUM_YINJIE; i++)
		for(k = pMhi->nYjOff[i]; k < pMhi->nYjOff[i + 1]; k++)
			*(pMhArea + k) ^= (BYTE)((i + 56) / 2);

	for(i = 0; i < NUM_YINJIE; i++)
		for(k = pGbki->nYjOff[i]; k < pGbki->nYjOff[i + 1]; k++)
			*(pGbkArea + k) ^= (BYTE)((i + 56) / 2);

	return TRUE;
}


JINT WriteCikuData(CHAR* szSysCikuName, JINT nTimeStamp)
{
	FILE*   pfCiku;
	JINT    i, k;
	JINT    nFileSize;
	
	CikuHeader  *pCkh;
	ShIndex     *pShi;
	DhIndex     *pDhi;
	MhIndex     *pMhi;
	GbkIndex    *pGbki;
	BYTE        *pShArea;
	BYTE        *pDhArea;
	BYTE        *pMhArea;
	BYTE        *pGbkArea;

	pCkh     = (CikuHeader *)pCkAll;
	pShi     = (ShIndex  *)(pCkAll + pCkh->nIdxShPos);
	pDhi     = (DhIndex  *)(pCkAll + pCkh->nIdxDhPos);
	pMhi     = (MhIndex  *)(pCkAll + pCkh->nIdxMhPos);
	pGbki    = (GbkIndex *)(pCkAll + pCkh->nIdxGbkPos);
	
	pShArea  = (BYTE *)(pCkAll + pShi->nStartPos);
	pDhArea  = (BYTE *)(pCkAll + pDhi->nStartPos);
	pMhArea  = (BYTE *)(pCkAll + pMhi->nStartPos);
	pGbkArea = (BYTE *)(pCkAll + pGbki->nStartPos);
	
	pCkh->nLatestTime = nTimeStamp;
	
	for(i = 0; i < NUM_YINJIE; i++)
		for(k = (pShi->nYjOff[i] & 0x00FFFFFF); k < (pShi->nYjOff[i + 1] & 0x00FFFFFF); k++)
			*(pShArea + k) ^= (BYTE)((i + 56) / 2);

	for(i = 0; i < NUM_YINJIE; i++)
		for(k = pDhi->nYjOff[i]; k < pDhi->nYjOff[i + 1]; k++)
			*(pDhArea + k) ^= (BYTE)((i + 56) / 2);

	for(i = 0; i < NUM_YINJIE; i++)
		for(k = pMhi->nYjOff[i]; k < pMhi->nYjOff[i + 1]; k++)
			*(pMhArea + k) ^= (BYTE)((i + 56) / 2);
	
	for(i = 0; i < NUM_YINJIE; i++)
		for(k = pGbki->nYjOff[i]; k < pGbki->nYjOff[i + 1]; k++)
			*(pGbkArea + k) ^= (BYTE)((i + 56) / 2);

	/* Write These data back to file */
	pfCiku = fopen(szSysCikuName, "wb");
	if (pfCiku == NULL)
	{
		fprintf(stderr, "Failed to Create System Ciku File: %s\n", szSysCikuName);
		return FALSE;
	}
	
	nFileSize = pCkh->nFileSize;
	if ((JINT)fwrite (pCkAll, 1, nFileSize, pfCiku) != nFileSize )
	{
		fprintf(stderr, "Failed to fwrite() System Ciku File.\n");
		return FALSE;
	}
	
	return TRUE;
}


/*  
**  pnSize:     If nMode is LU_SYSCANDI_CALC, Calculate the size need totally to contain all those SysCandis,
**              and set nNumShCandi, nNumDhCandi, nNumMhCandi, nSizShCandi, nSizDhCandi, nSizMhCandi of struct psc.
**              [pnSize is in JWORD]
**
**  nMatchMode: LU_MATCH_STRICT   ==> Match Strictly. Used by nLenYj >= 5. Condition: nCzLen == nLenYj  
**              LU_MATCH_WIDELY   ==> Match Widely.   Used by nLenYj >= 5. Condition: nCzLen >= nLenYj
**              Condition for LU_MATCH_WIDLY:
**                        zhong hua ren min gong // zhong hua ren min gong h  // zhong hua ren min gong he
**              Condition for LU_MATCH_STRICT:  => Last YjString is unmatched and meanless.
**                        zhong hua ren min gong [go gon cho chon cua]
**
**  nMode:      LU_SYSCANDI_WRITE ==> Write all those SysCandis to allocated memory for Sh, Dh, Mh Candidates.
**                                    [Certainly, make *pwShCandi, *pwDhCandi, *pwMhCandi point to *(pwCandiBuf + ?) first.]
**              LU_SYSCANDI_CALC  ==> Calculate the space size which needed to contain all those SysCandis.
**
**  NOTES:      Structure psc was filled after two calling of this function: First in Mode LU_SYSCANDI_CALC,
**              second in Mode LU_SYSCANDI_WRITE.
**
**  Content of pwCandiBuf == pwMhCandi + pwDhCandi + pwShCandi + 0x0000
**             Mh: fhhhhhh0fhhh0fhhhh0
**             Dh: fhh0fhh0fhh0fhh0fhh0fhh0fhh0fhh0fhh0fhh0fhh0fhh0
**             Sh: XX0XX0h0h0h0h0h0h0h0h0h0h0h0 + 0     OR
**                 Q0Q0Q0Q0Q0Q0Q0h0h0h0h0h0h0h0h0 + 0
*/
JINT EnumSysCandi(JINT* pnOrgYj, JINT nLenYj, SysCandi* psc, JINT* pnSize, JWORD* pwCandiBuf, JINT nMatchMode, JINT nMode)
{
	JINT    nFromOff, nToOff;
	JINT    nFromYj, nToYj, nTmp, nXianNum;	  /* For Single Hanzi Area Searching */
	UCHAR   chHi, chLow;                      /* For Single Hanzi Area Searching */
	JINT    nCzLen, m, k;
	JWORD   wCzHz[10], wMhLenFreq, wDhFreq;
	JINT    nEqualFlag;
	CHAR    *pszYj1, *pszYj2;                 /* For DhCandi, compare string directly */
	CHAR    szYj3[12], szYj4[12];
	
	CikuHeader  *pCkh;
	ShIndex     *pShi;
	DhIndex     *pDhi;
	MhIndex     *pMhi;
	BYTE        *pShArea;
	BYTE        *pDhArea;
	BYTE        *pMhArea;
	
	pCkh    = (CikuHeader *)pCkAll;
	pShi    = (ShIndex *)(pCkAll + pCkh->nIdxShPos);
	pDhi    = (DhIndex *)(pCkAll + pCkh->nIdxDhPos);
	pMhi    = (MhIndex *)(pCkAll + pCkh->nIdxMhPos);
	
	pShArea = (BYTE *)(pCkAll + pShi->nStartPos);
	pDhArea = (BYTE *)(pCkAll + pDhi->nStartPos);
	pMhArea = (BYTE *)(pCkAll + pMhi->nStartPos);

	if (nMode == LU_SYSCANDI_CALC)
		*pnSize  = 0;
	else if (nMode == LU_SYSCANDI_WRITE)
	{
		psc->pwMhCandi   = pwCandiBuf;
		psc->pwDhCandi   = pwCandiBuf + psc->nSizMhCandi;
		psc->pwShCandi   = pwCandiBuf + psc->nSizMhCandi + psc->nSizDhCandi;
			
		psc->nSizMhCandi = 0;
		psc->nSizDhCandi = 0;
		psc->nSizShCandi = 0;
			
		psc->nNumMhCandi = 0;
		psc->nNumDhCandi = 0;
		psc->nNumShCandi = 0;
	}

	if (nLenYj >= 3)
	{
		/*
		**  Determine the FromOff and ToOff which to used for searching by the pnOrgYj[0].
		*/
		if ((pnOrgYj[0] >= 0) && (pnOrgYj[0] < NUM_YINJIE))
		{
			nFromOff = pMhi->nYjOff[ pnOrgYj[0] ];
			nToOff   = pMhi->nYjOff[ pnOrgYj[0] + 1];
		}
		else   /* ((pnOrgYj[0] >= 450) && (pnOrgYj[0] <= 475)) */
		{
			nFromOff = pMhi->nYjOff[ INDEXSMTOYINJIE[pnOrgYj[0] - 450] ];
			nToOff   = pMhi->nYjOff[ INDEXSMTOYINJIE[pnOrgYj[0] - 450 + 1] ];
		}
	
		/* !! DON'T add k++ in this FOR sentence !! */
		for (k = nFromOff; k < nToOff; )
		{
			wMhLenFreq = (JWORD)*(pMhArea + k);
			nCzLen     = 2 + ((UCHAR)*(pMhArea + k) & 0x07);
			k++;
			
			for (m = 0; m < 10; m++)
				wCzHz[m]   = 0x0000;
			for (m = 0; m < nCzLen; m++)
			{
				wCzHz[m]   = (JWORD)(*(pMhArea + k + 1) + ((*(pMhArea + k)) << 8));
				k += 2;
			}
			
			/*
			** DON'T CONVERT wCzItem into YJSTRING and CALL ParsePreedit() HERE, BECAUSE THAT
			** IS TOO COMPLEX AND UN_LOGICALLY.
			** For Example, zai xian shi qu ==> zai xi'an shi qu [Four ~ Five !!!!]
			*/
			nEqualFlag = FALSE;
			if ( ((nCzLen == nLenYj) && ((nLenYj == 3) || (nLenYj == 4))) || 
			     ((nCzLen >= nLenYj) && (nLenYj >= 5)  && (nMatchMode == LU_MATCH_WIDELY)) ||
			     ((nCzLen == nLenYj) && (nLenYj >= 5)  && (nMatchMode == LU_MATCH_STRICT)) )
			{
				nEqualFlag = TRUE;
				
				for(m = 1; m < nLenYj; m++)
					if ( ( pnOrgYj[m] != Hzcode2244ToYjSMcode((JINT)wCzHz[m]) ) && 			\
					     ( pnOrgYj[m] != Hzcode2244ToYjcode((JINT)wCzHz[m])   ) )
					{
						nEqualFlag = FALSE;
						break;
					}
			}
			
			if ((nEqualFlag == TRUE) && (nMode == LU_SYSCANDI_CALC))
			{
				psc->nSizMhCandi += (nCzLen + 2);	/* Add two JWORD Here to contain Freq&Len Word and a ZERO */
				psc->nNumMhCandi += 1;
				*pnSize += (nCzLen + 2);
			}
			else if ((nEqualFlag == TRUE) && (nMode == LU_SYSCANDI_WRITE))
			{
				psc->pwMhCandi[psc->nSizMhCandi] = wMhLenFreq;
				for (m = 0; m < nCzLen; m++)
					psc->pwMhCandi[psc->nSizMhCandi + m + 1] = wCzHz[m];
				
				psc->nSizMhCandi += (nCzLen + 2);
				psc->nNumMhCandi += 1;
				*pnSize += (nCzLen + 2);
			}
		}
	}
	

	if (nLenYj >= 2)
	{
		/*
		**  Determine the FromOff and ToOff which to used for searching by the pnOrgYj[0].
		*/
		if ((pnOrgYj[0] >= 0) && (pnOrgYj[0] < NUM_YINJIE))
		{
			nFromOff = pDhi->nYjOff[ pnOrgYj[0] ];
			nToOff   = pDhi->nYjOff[ pnOrgYj[0] + 1];
		}
		else /* ((pnOrgYj[0] >= 450) && (pnOrgYj[0] <= 475)) */
		{
			nFromOff = pDhi->nYjOff[ INDEXSMTOYINJIE[pnOrgYj[0] - 450] ];
			nToOff   = pDhi->nYjOff[ INDEXSMTOYINJIE[pnOrgYj[0] - 450 + 1] ];
		}
	
		/* !! DON'T add k++ in this FOR sentence !! */
		for (k = nFromOff; k < nToOff; )
		{
			wDhFreq  = (JWORD)*(pDhArea + k);
			nCzLen   = 2;
			k ++;

			for (m = 0; m < 10; m++)
				wCzHz[m]   = 0x0000;
			for (m = 0; m < nCzLen; m++)
			{
				wCzHz[m]   = (JWORD)(*(pDhArea + k + 1) + ((*(pDhArea + k)) << 8));
				k += 2;
			}

			for (m = 0; m < 12; m++)
			{
				szYj3[m]   = '\0';
				szYj4[m]   = '\0';
			}
			
			if ((pnOrgYj[0] >= 450) && (pnOrgYj[0] <= 475))
				pszYj1 = SHENGMUSTR[ pnOrgYj[0] - 450 ];
			else      /* ((pnOrgYj[0] >= 0) && (pnOrgYj[0] < 415)) */
				pszYj1 = YINJIESTR_CSZ[ pnOrgYj[0] ];

			if ((pnOrgYj[1] >= 450) && (pnOrgYj[1] <= 475))
				pszYj2 = SHENGMUSTR[ Hzcode2244ToYjSMcode((JINT)wCzHz[1]) - 450];
			else      /*  ((pnOrgYj[1] >= 0) && (pnOrgYj[1] < 415))  */
				pszYj2 = YINJIESTR_CSZ[Hzcode2244ToYjcode( (JINT)wCzHz[1] )];
			strcat(strcat(szYj3, pszYj1), pszYj2);
			
			if ((pnOrgYj[1] >= 450) && (pnOrgYj[1] <= 475))
				pszYj2 = SHENGMUSTR[ pnOrgYj[1] - 450 ];
			else if ((pnOrgYj[1] >= 0) && (pnOrgYj[1] < 415))
				pszYj2 = YINJIESTR_CSZ[ pnOrgYj[1] ];
			strcat(strcat(szYj4, pszYj1), pszYj2);

			nEqualFlag = TRUE;
			if ( strcmp (szYj3, szYj4) != 0)
				nEqualFlag = FALSE;
			
			if ((nEqualFlag == TRUE) && (nMode == LU_SYSCANDI_CALC))
			{
				psc->nSizDhCandi += (nCzLen + 2);	/* Add two JWORD Here to contain Freq Word and a ZERO */
				psc->nNumDhCandi += 1;
				*pnSize += (nCzLen + 2);
			}
			else if ((nEqualFlag == TRUE) && (nMode == LU_SYSCANDI_WRITE))
			{
				psc->pwDhCandi[psc->nSizDhCandi] = wDhFreq;
				for (m = 0; m < nCzLen; m++)
					psc->pwDhCandi[psc->nSizDhCandi + m + 1] = wCzHz[m];
				
				psc->nSizDhCandi += (nCzLen + 2);
				psc->nNumDhCandi += 1;
				*pnSize += (nCzLen + 2);
			}
		}
	}

	if (nLenYj >= 1)
	{
		/*
		**  Order of Single Hanzi Candidates:
		**  IF pnOrgYj[0] is a SM, place HIFREQHANZI[?][14] at the head of ShCandi Area
		**                         Place Single Hanzi by Frequence and Yinjie Sequence
		**  IF pnOrgYj[0] is Normal Yinjie [0 ~ 414], place XianForm candis at the head.
		**                         place Single Hanzi by Frequence and Yinjie Sequence
		**
		**  Determine the Fromyj and ToYj which to used for searching by the pnOrgYj[0].
		**  NOTICE: This is different from DhCandi and MhCandi.  
		*/
		if ((pnOrgYj[0] >= 0) && (pnOrgYj[0] < NUM_YINJIE))
		{
			nFromYj  = pnOrgYj[0];
			nToYj    = pnOrgYj[0] + 1;

			nXianNum = (pShi->nYjOff[nToYj] & 0x0F000000) >> 24;
			for (k = 0; k < nXianNum; k++)
			{
				if (nMode == LU_SYSCANDI_CALC)
				{
					psc->nSizShCandi += 3;	  /* Add one ZERO After this Xian Candi */
					psc->nNumShCandi += 1;
					*pnSize += 3;
				}
				else if (nMode == LU_SYSCANDI_WRITE)
				{
					nTmp  = pShi->nYjOff[nToYj] & 0x00FFFFFF;
					chHi  = (UCHAR)*(pShArea + nTmp - (nXianNum * 4) + (k * 4));
					chLow = (UCHAR)*(pShArea + nTmp - (nXianNum * 4) + (k * 4) + 1);
					psc->pwShCandi[psc->nSizShCandi]     = (JWORD)((chHi << 8) + chLow);
					
					chHi  = (UCHAR)*(pShArea + nTmp - (nXianNum * 4) + (k * 4) + 2);
					chLow = (UCHAR)*(pShArea + nTmp - (nXianNum * 4) + (k * 4) + 3);
					psc->pwShCandi[psc->nSizShCandi + 1] = (JWORD)((chHi << 8) + chLow);
					
					psc->pwShCandi[psc->nSizShCandi + 2] = 0x0000;

					psc->nSizShCandi += 3;
					psc->nNumShCandi += 1;
					*pnSize += 3;
				}
			}
		}
		else   /* ((pnOrgYj[0] >= 450) && (pnOrgYj[0] <= 475)) */
		{
			nFromYj  = INDEXSMTOYINJIE[ pnOrgYj[0] - 450 ];
			nToYj    = INDEXSMTOYINJIE[ pnOrgYj[0] - 450 + 1 ];

			for (m = 0; m < 7; m++)         /* There are 7 HIFREQHANZI in each SM Yinjie. See PyBasic.h */
			{
				if (nMode == LU_SYSCANDI_CALC)
				{
					psc->nSizShCandi += 2;	  /* Add one ZERO After this HIFREQHANZI */
					psc->nNumShCandi += 1;
					*pnSize += 2;
				}
				else if (nMode == LU_SYSCANDI_WRITE)
				{
					chHi  = HIFREQHANZI[pnOrgYj[0] - 450][2 * m];
					chLow = HIFREQHANZI[pnOrgYj[0] - 450][2 * m + 1];
					psc->pwShCandi[psc->nSizShCandi]     = (JWORD)((chHi << 8) + chLow);
					
					psc->nSizShCandi += 2;
					psc->nNumShCandi += 1;
					*pnSize += 2;
				}
			}
		}
		
		/*
		**  Because 'Xian' Form is already included in above processing (0 ~ 414), and no necessary
		**  for (450 ~ 475), So, not to include then in the following reclycle.
		*/
		for(k = nFromYj; k < nToYj; k++)
		{
			nXianNum = (pShi->nYjOff[k + 1] & 0x0F000000) >> 24;
			nFromOff = pShi->nYjOff[ k ] & 0x00FFFFFF;
			nToOff   = (pShi->nYjOff[ k + 1] & 0x00FFFFFF) - (4 * nXianNum);
			
			/* !!Don't add m++ in this FOR sentence!! */
			for(m = nFromOff; m < nToOff;  )
			{
				if (nMode == LU_SYSCANDI_CALC)
				{
					psc->nSizShCandi += 2;	  /* Add one ZERO After each Single Hanzi Candidate */
					psc->nNumShCandi += 1;
					*pnSize += 2;
					m += 2;
				}
				else if (nMode == LU_SYSCANDI_WRITE)
				{
					chHi  = (UCHAR)*(pShArea + m);
					chLow = (UCHAR)*(pShArea + m + 1);
					psc->pwShCandi[psc->nSizShCandi]   = (JWORD)((chHi << 8) + chLow);
					
					psc->nSizShCandi += 2;
					psc->nNumShCandi += 1;
					*pnSize += 2;
					m += 2;
				}
			}
		}
	}
	
	*pnSize += 1;
	
	return TRUE;
}


VOID InitStructSc(SysCandi* psc)
{
	JINT    i;
	
	for(i = 0; i < 9; i++)
		psc->nOrgYj[i]     = 0xFFFF;

	psc->nLenYj      = 0;

	psc->nNumShCandi = 0;
	psc->pwShCandi   = NULL;
	
	psc->nNumDhCandi = 0;
	psc->pwDhCandi   = 0;
	
	psc->nNumMhCandi = 0;
	psc->pwMhCandi   = NULL;
	
	psc->nSizShCandi = 0;
	psc->nSizDhCandi = 0;
	psc->nSizMhCandi = 0;
}


/*
**  nLenYj indicates the length of pnOrgYj. 
**  Max Length of nLenYj is 9, even Max Hanzi Length in
**  current PyCiku.dat is 7.
*/
SysCandi* LookupSysCiku(JINT* pnOrgYj, JINT nLenYj, JINT nMatchMode)
{
	JINT      nSize, i;
	SysCandi  *pscSC;
	static  JWORD  *pwCandiBuf;

	pscSC = (SysCandi*)malloc(sizeof(SysCandi));
	if(pscSC == NULL)
	{
		fprintf(stderr, "Failed to alloc memory for struct pscSC in LookupSysCiku().\n");
		exit(FALSE);
	}

	nSize = 0;
	InitStructSc(pscSC);
	if (pwCandiBuf != NULL)
		free(pwCandiBuf);
	
	EnumSysCandi(pnOrgYj, nLenYj, pscSC, &nSize, pwCandiBuf, nMatchMode, LU_SYSCANDI_CALC);
	
	pwCandiBuf = (JWORD *)malloc(nSize * sizeof(JWORD));
	if (pwCandiBuf == NULL)
	{
		fprintf(stderr, "Error!! Failed to Malloc() in Function LookupSysCiku().\n");
		exit(FALSE);
	}
	for(i = 0; i < nSize; i++)
		*(pwCandiBuf + i) = 0x0000;
	
	printf("MhCandi[%d]  DhCandi[%d]  ShCandi[%d]. TotalSize in JWORD[%d]\n", 
		pscSC->nNumMhCandi, pscSC->nNumDhCandi, pscSC->nNumShCandi, nSize);
	
	EnumSysCandi(pnOrgYj, nLenYj, pscSC, &nSize, pwCandiBuf, nMatchMode, LU_SYSCANDI_WRITE);
	
	/* Sort Candidates in struct SysCandi by Frequence */
	SortSysCandi(pscSC);
	
	return (pscSC);
}


/*
**  Sort Candidates in Structure SysCandi by Length and Frequence
*/
VOID SortSysCandi(SysCandi* psc)
{
	JINT    nNumM, nSizM, nNumD, nSizD;
	JWORD   *pwBuf;
	JINT    nBuf, nTmp, i, k, m, n, p, nLenM, nFreqM;
	
	nNumM   = psc->nNumMhCandi;
	nSizM   = psc->nSizMhCandi;
	nNumD   = psc->nNumDhCandi;
	nSizD   = psc->nSizDhCandi;

	if ((nNumM <= 1) && (nNumD <= 1))
		return;
	
	if(nSizM > nSizD)
		nBuf = nSizM;
	else
		nBuf = nSizD;
	
	pwBuf = (JWORD *)malloc(nBuf * sizeof(JWORD));
	if (pwBuf == NULL)
	{
		fprintf(stderr, "Failed to alloc Memory in function SortSysCandi().\n");
		exit(FALSE);
	}
	
	/*
	**  For MultipleHanzi Candidates, by Length First, by Frequence Second.
	*/
	nLenM = nFreqM = 0;
	if(nNumM > 1)
	{
		for(i = 0; i < nBuf; i++)
			pwBuf[i]  = 0x0000;
			
		p = m = n = 0;
		for(i = 0xFF; (i >= 0x00) && (p < nNumM); i--)
		{
			for(k = 0; k < nSizM; k++)
			{
				/*
				**  Exchange [Freq + Len] to [Len + Freq] (nTmp)
				*/
				nLenM  = psc->pwMhCandi[k] & 0x07;
				nFreqM = psc->pwMhCandi[k] & 0xF8;
				nTmp   = (nLenM << 5) + (nFreqM >> 3);
				if(nTmp == i)
				{
					for(m = 0; m < (nLenM + 4); m++)
						pwBuf[n++] = psc->pwMhCandi[k + m];
					p++;
				}
			}
		}
		
		for(i = 0; i < nSizM; i++)
			psc->pwMhCandi[i] = pwBuf[i];
	}
	
	/*
	**  For DoubleHanzi Candidates, by Frequence only.
	*/
	if(nNumD > 1)
	{
		for(i = 0; i < nBuf; i++)
			pwBuf[i]  = 0x0000;
	
		p = m = n = 0;
		for(i = 0xFF; (i >= 0x00) && (p < nNumD); i--)
		{
			for(k = 0; k < nSizD; k++)
			{
				nTmp   = psc->pwDhCandi[k];
				if(nTmp == i)
				{
					for(m = 0; m < 4; m++)
						pwBuf[n++] = psc->pwDhCandi[k + m];
					p++;
				}
			}
		}
		
		for(i = 0; i < nSizD; i++)
			psc->pwDhCandi[i] = pwBuf[i];
	}
}


/*
**  Adjust the freqence of a specified Ciku. Length of this cizu is 
**  specified in nLen.
**
**  Increase the frequence of this Dh or Mh, decrease the frequence
**  of other Dh or Mh which have same Yjcode.
**
**  For Sh, move the Hanzi forward to a certain place, move other
**  Hanzies backward.
*/
VOID AdjustFreq(JWORD* pwHz2244, JINT nLenThis)
{
	JINT    nYjFirst;
	JINT    nCzLen, i, k, m, t;
	JINT    nFromOff, nToOff;
	JWORD   wCzHz, wMhLenFreq, wFreq;
	JINT    nEqualFlag;
	CHAR    szDhYj1[12], szDhYj2[12];

	CikuHeader  *pCkh;
	ShIndex     *pShi;
	DhIndex     *pDhi;
	MhIndex     *pMhi;
	BYTE        *pShArea;
	BYTE        *pDhArea;
	BYTE        *pMhArea;
	
	pCkh    = (CikuHeader *)pCkAll;
	pShi    = (ShIndex *)(pCkAll + pCkh->nIdxShPos);
	pDhi    = (DhIndex *)(pCkAll + pCkh->nIdxDhPos);
	pMhi    = (MhIndex *)(pCkAll + pCkh->nIdxMhPos);
	pShArea = (BYTE *)(pCkAll + pShi->nStartPos);
	pDhArea = (BYTE *)(pCkAll + pDhi->nStartPos);
	pMhArea = (BYTE *)(pCkAll + pMhi->nStartPos);

	/* nYjFirst must be in range 0~414 */
	nYjFirst = Hzcode2244ToYjcode((JINT)pwHz2244[0]);

	if (nLenThis >= 3)
	{
		/*
		**  Determine the FromOff and ToOff which to used for searching by the pnOrgYj[0].
		*/
		nFromOff = pMhi->nYjOff[ nYjFirst ];
		nToOff   = pMhi->nYjOff[ nYjFirst + 1];
		
		/* !! DON'T add k++ in this FOR sentence !! */
		for (k = nFromOff; k < nToOff; )
		{
			wMhLenFreq = (JWORD)*(pMhArea + k);
			nCzLen     = 2 + ((UCHAR)*(pMhArea + k) & 0x07);
			k++;

			/*  It is just this Cizu, Increase its frequence here. */
			if ((nCzLen == nLenThis) &&
				(strncmp((CHAR*)(&pMhArea[k]), (CHAR*)pwHz2244, 2 * nCzLen) == 0) )
			{
				/* Just set Frequence to highest. */
				*(pMhArea + k - 1) = (BYTE)(0xF8 + (nCzLen - 2));
				k += (2 * nCzLen);
			}
			/*
			**  Have the same length. Is it also have same Yjcode? If yes, 
			**  reduce the frequence.
			*/
			else if ((nCzLen == nLenThis) &&
				(strncmp((CHAR*)(&pMhArea[k]), (CHAR*)pwHz2244, 2 * nCzLen) != 0) )
			{
				nEqualFlag = TRUE;

				/*
				** Compare from the second Hanzi, because the first Hanzi must
				** same Yjcode. So, skip the first by adding t += 2.
				*/
				t = k;
				t += 2;
				for (m = 1; m < nCzLen; m++)
				{
					wCzHz   = (JWORD)(*(pMhArea + t + 1) + ((*(pMhArea + t)) << 8));
					t += 2;

					if ( Hzcode2244ToYjcode((JINT)pwHz2244[1]) != Hzcode2244ToYjcode((JINT)wCzHz) )
					{
						nEqualFlag = FALSE;
						break;
					}
				}

				/* Have same Yjcodes in every Hanzi, reduce its Frequence Here. */
				if (nEqualFlag == TRUE)
				{
					wMhLenFreq = (JWORD)*(pMhArea + k - 1);
					/*
					** Length bits have the lowest 3 bits.  -8 means reduce the Frequence
					** by ONE level. if its Freq Level is 1, no reduce needed.
					*/
					if (wMhLenFreq >= 16)
						*(pMhArea + k - 1) -= 8;
				}

				k += (2 * nCzLen);
			}
			/* If it doesn't have the same length, just skip this cizu. */
			else
				k += (2 * nCzLen);
		}
	}
	
	else if (nLenThis == 2)
	{
		/*
		**  Determine the FromOff and ToOff which to used for searching by the pnOrgYj[0].
		*/
		nFromOff = pDhi->nYjOff[ nYjFirst ];
		nToOff   = pDhi->nYjOff[ nYjFirst + 1];
		
		/* !! DON'T add k++ in this FOR sentence !! */
		for (k = nFromOff; k < nToOff; )
		{
			wFreq   = (JWORD)*(pDhArea + k);
			nCzLen  = 2;
			k++;

			/*  It is just this Cizu, Increase its frequence here. */
			if (strncmp((CHAR*)(&pDhArea[k]), (CHAR*)pwHz2244, 4) == 0)
			{
				/* Just set Frequence to highest. */
				*(pDhArea + k - 1) = 0xFF;
				k += 4;
				printf("YES. Increase Freq Just This.\n");
			}
			/*
			**  Have the same length. Is it also have same Yjcode? If yes, 
			**  reduce the frequence.
			*/
			else
			{
				for(i = 0; i < 12; i++)
					szDhYj1[i] = szDhYj2[i] = '\0';

				/* Cat total YinjieString into szDhYj1 */
				strcat( strcat(szDhYj1, YINJIESTR_CSZ[nYjFirst]),	
				                        YINJIESTR_CSZ[Hzcode2244ToYjcode((JINT)pwHz2244[1])] );

				t = k;
				wCzHz   = (JWORD)(*(pMhArea + t + 1) + ((*(pMhArea + t)) << 8));
				strcat(szDhYj2, YINJIESTR_CSZ[Hzcode2244ToYjcode((JINT)wCzHz)]);

				t += 2;
				wCzHz   = (JWORD)(*(pMhArea + t + 1) + ((*(pMhArea + t)) << 8));
				strcat(szDhYj2, YINJIESTR_CSZ[Hzcode2244ToYjcode((JINT)wCzHz)]);

				nEqualFlag = TRUE;
				if (strcmp(szDhYj1, szDhYj2) != 0)
					nEqualFlag = FALSE;

				/* Have same Yjcodes in every Hanzi, reduce its Frequence Here. */
				if (nEqualFlag == TRUE)
				{
					wFreq = (JWORD)*(pDhArea + k - 1);
					/*
					** Decrease by ONE Level.
					*/
					if (wFreq >= 2)
						*(pDhArea + k - 1) -= 1;
					
					printf("YES. Decrease Freq Here!!!!\n");
				}
				k += 4;

			}
		}
	}

}


