/*******************************************************************************
;*******************************************************************************
;**                                                                           **
;**                  COPYRIGHT 2012 NUANCE COMMUNICATIONS                     **
;**                                                                           **
;**               NUANCE COMMUNICATIONS PROPRIETARY INFORMATION               **
;**                                                                           **
;**     This software is supplied under the terms of a license agreement      **
;**     or non-disclosure agreement with Nuance Communications and may not    **
;**     be copied or disclosed except in accordance with the terms of that    **
;**     agreement.                                                            **
;**                                                                           **
;*******************************************************************************
;**                                                                           **
;**     FileName: ET9KUtil.c                                                 **
;**                                                                           **
;**  Description: Simple example functions of wrapping ET9 Korean API to      **
;**               decombine double consonants to single consonants for        **
;**               the Choseong searching feature                              **
;**                                                                           **
;*******************************************************************************
;******************************************************************************/

#include "et9kutil.h"
#include "et9kapi.h"
#include "et9misc.h"

/*---------------------------------------------------------------------------*/

typedef struct JaCombineMap_s
{
    ET9SYMB sJa1;
    ET9SYMB sJa2;
} JaCombineMap;

/*---------------------------------------------------------------------------*/

static const JaCombineMap COMP_DOUBLE_JA_COMBO_MAP[] = {
    {0x3131, 0x3145}, /* 0x3133 */
    {0x0000, 0x0000}, /* 0x3134 */
    {0x3134, 0x3148}, /* 0x3135 */
    {0x3134, 0x314E}, /* 0x3136 */
    {0x0000, 0x0000}, /* 0x3137 */
    {0x0000, 0x0000}, /* 0x3138 */
    {0x0000, 0x0000}, /* 0x3139 */
    {0x3139, 0x3131}, /* 0x313a */
    {0x3139, 0x3141}, /* 0x313b */
    {0x3139, 0x3142}, /* 0x313c */
    {0x3139, 0x3145}, /* 0x313d */
    {0x3139, 0x314C}, /* 0x313e */
    {0x3139, 0x314d}, /* 0x313f */
    {0x3139, 0x314E}, /* 0x3140 */
    {0x0000, 0x0000}, /* 0x3141 */
    {0x0000, 0x0000}, /* 0x3142 */
    {0x0000, 0x0000}, /* 0x3143 */
    {0x3142, 0x3145}  /* 0x3144 */
};
static const ET9UINT COMP_DOUBLE_JA_COMBO_MAP_FIRST = 0x3133;
static const ET9UINT COMP_DOUBLE_JA_COMBO_MAP_COUNT
    = sizeof(COMP_DOUBLE_JA_COMBO_MAP) / sizeof(COMP_DOUBLE_JA_COMBO_MAP[0]);

static const JaCombineMap DOUBLE_JA_COMBO_MAP[] = {
    {0x1100, 0x1109}, /* 0x11aa */
    {0x0000, 0x0000}, /* 0x11ab */
    {0x1102, 0x110c}, /* 0x11ac */
    {0x1102, 0x1112}, /* 0x11ad */
    {0x0000, 0x0000}, /* 0x11ae */
    {0x0000, 0x0000}, /* 0x11af */
    {0x1105, 0x1100}, /* 0x11b0 */
    {0x1105, 0x1106}, /* 0x11b1 */
    {0x1105, 0x1107}, /* 0x11b2 */
    {0x1105, 0x1109}, /* 0x11b3 */
    {0x1105, 0x1110}, /* 0x11b4 */
    {0x1105, 0x1111}, /* 0x11b5 */
    {0x1105, 0x1112}, /* 0x11b6 */
    {0x0000, 0x0000}, /* 0x11b7 */
    {0x0000, 0x0000}, /* 0x11b8 */
    {0x1107, 0x1109}  /* 0x11b9 */
};
static const ET9SYMB DOUBLE_JA_COMBO_MAP_FIRST = 0x11aa;
static const ET9UINT DOUBLE_JA_COMBO_MAP_COUNT
    = sizeof(DOUBLE_JA_COMBO_MAP) / sizeof(DOUBLE_JA_COMBO_MAP[0]);

/*---------------------------------------------------------------------------*/

static ET9BOOL IsCombo(const JaCombineMap * const pMap,
                       ET9UINT                    nMapSize,
                       ET9SYMB                    sMapFirst,
                       ET9SYMB                    symb,
                       ET9SYMB            * const pJa1,
                       ET9SYMB            * const pJa2)
{
   ET9INT i = symb - sMapFirst;

    if ( 0 <= i && i < (ET9INT)nMapSize )
    {
        if (pMap[i].sJa1)
        {
            *pJa1 = pMap[i].sJa1;
            *pJa2 = pMap[i].sJa2;
            return 1;
        }
    }

    return 0;
}

static ET9STATUS Decombine(const ET9KHangulWord * const pHangulSrc,
                           ET9BOOL                      isCompJamo,
                           ET9KHangulWord       * const pHangulDest)
{
    ET9U16                i, j;
    ET9SYMB               ja1, ja2;
    const JaCombineMap  * jaMap;
    ET9U16                jaMapSize;
    ET9SYMB               jaMapFirstCode;

    if ( pHangulDest == NULL )  
    {
        return ET9STATUS_INVALID_MEMORY;
    }

    if ( isCompJamo )
    {
        jaMap          = COMP_DOUBLE_JA_COMBO_MAP;
        jaMapSize      = COMP_DOUBLE_JA_COMBO_MAP_COUNT;
        jaMapFirstCode = COMP_DOUBLE_JA_COMBO_MAP_FIRST;
    }
    else
    {
        jaMap          = DOUBLE_JA_COMBO_MAP;
        jaMapSize      = DOUBLE_JA_COMBO_MAP_COUNT;
        jaMapFirstCode = DOUBLE_JA_COMBO_MAP_FIRST;
    }

    pHangulDest->wLen      = pHangulSrc->wLen;
    pHangulDest->wComplete = pHangulSrc->wComplete;

    for ( i = 0, j = 0; i < pHangulSrc->wLen; i++, j++ )
    {
        if ( IsCombo(jaMap, jaMapSize, jaMapFirstCode, pHangulSrc->sString[i], &ja1, &ja2) )
        {
            pHangulDest->sString[j]     = ja1;
            pHangulDest->pSymbCounts[j++] = 1;

            pHangulDest->sString[j]   = ja2;
            pHangulDest->pSymbCounts[j] = 1;

            pHangulDest->wComplete++;
            pHangulDest->wLen++;
        }
        else
        {
            pHangulDest->sString[j]     = pHangulSrc->sString[i];
            pHangulDest->pSymbCounts[j] = pHangulSrc->pSymbCounts[i];
        }
    }

    return ET9STATUS_NONE;
}

/*---------------------------------------------------------------------------*/

/**
 * This function wraps the ET9KGetHangul function and decombine initial jamo consonants
 * into single symbol representations
 * Please call this function instead of ET9KGetHangul only when absolutely necessary
 *
 * After ET9KBuildSelectionList(), this function can be called to get specified hangul from the selection list
 *
 * @param pKLingInfo                Pointer to alphabetic information structure.
 * @param bHangulIndex              Hangul index of base 0.
 * @param psHangulBuf               Pointer to an adddress for the output Hangul.
 * @param wHangulBufLen             Size of psHangulBuf (number of ET9SYMB).
 * @param pwHangulLen               Pointer to an adddress for the length of output Hangul (number of ET9SYMB).
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */
 
ET9STATUS ET9FARCALL ET9KUTIL_GetHangulSingleConsonants(ET9KLingInfo * pKLingInfo, 
                                                        ET9U8          bHangulIndex, 
                                                        ET9SYMB      * psHangulBuf,
                                                        ET9U16         wHangulBufLen,
                                                        ET9U16       * pwHangulLen)
{
    ET9STATUS      status;
    ET9KHangulWord hangul1;
    ET9KHangulWord hangul2;

    status = ET9KGetHangul(pKLingInfo, bHangulIndex, hangul1.sString, sizeof(hangul1.sString)/sizeof(hangul1.sString[0]), &hangul1.wLen);
    if ( ET9STATUS_NONE == status )
    {
        status = Decombine(&hangul1,
                           ET9KOutputCompatibilityJamo(pKLingInfo),
                           &hangul2);
        if ( ET9STATUS_NONE == status )
        {
            if ( hangul2.wLen <= wHangulBufLen )
            {
                _ET9SymCopy(psHangulBuf, hangul2.sString, hangul2.wLen);
                *pwHangulLen = hangul2.wLen;
            }
    		else
    		{
                status = ET9STATUS_BUFFER_TOO_SMALL;
            }
        }
    }

    return status;
}

/**
 * This function wraps the ET9KBuildHangul function and decombine initial jamo consonants
 * into single symbol representations
 * Please call this function instead of ET9KBuildHangul only when absolutely necessary
 *
 * @param pKLingInfo            pointer to Korean linguistic module.
 * @param pHangul               for output of the Hangul string.
 * @param pMTSequence           array of symbs in an active mulitap sequence (NULL if not used).
 * @param wMTSymbCount          number of symbs in the multitap sequence (0 if not used).
 *
 * @return ET9STATUS_NONE           Succeeded
 * @return ET9STATUS_BAD_PARAM      one of the parameters is invalid
 * @return ET9STATUS_NO_INIT        system not properly initialized
 * @return ET9STATUS_INVALID_INPUT  system cannot interpret input
 * @return ET9STATUS_EMPTY          input buffer is empty
 */
ET9STATUS ET9FARCALL ET9KUTIL_BuildHangulSingleConsonants(ET9KLingInfo   * pKLingInfo,
                                                          ET9KHangulWord * pHangul,
                                                          const ET9SYMB  * pMTSequence,
                                                          ET9U16           wMTSymbCount)
{
    ET9STATUS      status;
    ET9KHangulWord hangul;

    status = ET9KBuildHangul(pKLingInfo, &hangul, pMTSequence, wMTSymbCount);
    if ( ET9STATUS_NONE == status )
    {
        status = Decombine(&hangul,
                           ET9KOutputCompatibilityJamo(pKLingInfo),
                           pHangul);
    }

    return status;
}

