/*******************************************************************************
;*******************************************************************************
;**                                                                           **
;**                    COPYRIGHT 1998-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: et9agdb.c                                                   **
;**                                                                           **
;**  Description: Gesture data base access routines source file.              **
;**                                                                           **
;*******************************************************************************
;******************************************************************************/

/*! \addtogroup et9agdb Gesture database for alphabetic
* Gesture features.
* @{
*/

#include "et9api.h"
#ifdef ET9_ALPHABETIC_MODULE
#include "et9asys.h"
#include "et9adb.h"
#include "et9agdb.h"
#include "et9amisc.h"
#include "et9asym.h"
#include "et9kbdef.h"
#include "et9aldb.h"

/*----------------------------------------------------------------------------
 * Defines
 *----------------------------------------------------------------------------*/

/* GDB data area pointer */

#define ET9GDBData(pGDB) ((ET9AWGDBRecord ET9FARDATA *)pGDB->sDataArea)

/* Standard gesture lengths */

#define ET9AWGDB_PUNCT_SPACE_GESTURE_LEN 2
#define ET9AWGDB_SINGLE_CHAR_SPACE_GESTURE_LEN 2
#define ET9AWGDB_SPACE_PUNCT_SPACE_GESTURE_LEN 3

/*---------------------------------------------------------------------------*/
/*  -IDR-    
 *                                                       
 *
 *                                                                
 *                                                                   
 *                                                   
 *                                                                    
 *
 *                                                                    
 */

static ET9STATUS ET9LOCALCALL __ET9AWGDBLanguageDependentGestureSearch(ET9AWLingInfo * const        pLingInfo,
                                                                       const ET9U16                 wIndex,
                                                                       const ET9U16                 wLength,
                                                                       const ET9_FREQ_DESIGNATION   bFreqIndicator)
{
    ET9AWLingCmnInfo * const pLingCmnInfo = pLingInfo->pLingCmnInfo;

    const ET9U32 dwLdbNum = pLingCmnInfo->dwLdbNum;
    const ET9BOOL bIsSecondLanguageActive = (dwLdbNum == pLingCmnInfo->dwSecondLdbNum ? 1 : 0);
    const ET9BOOL bIsInitialSpaceKey = pLingCmnInfo->Base.pWordSymbInfo->SymbsInfo[0].DataPerBaseSym[0].sChar[0] == (ET9SYMB)0x0020 ? 1 : 0;
    const ET9BOOL bIsTerminalSpaceKey = pLingCmnInfo->Base.pWordSymbInfo->SymbsInfo[pLingCmnInfo->Base.pWordSymbInfo->bNumSymbs - 1].DataPerBaseSym[0].sChar[0] == (ET9SYMB)0x0020 ? 1 : 0;

    ET9Assert(pLingInfo);
    ET9Assert(pLingCmnInfo);
    ET9Assert(pLingCmnInfo->Base.pWordSymbInfo);
    ET9Assert(pLingCmnInfo->Base.pWordSymbInfo->bNumSymbs);

    if (pLingCmnInfo->Base.pWordSymbInfo->bNumSymbs < 2 || _ET9_LanguageSpecific_IsNonGestureLanguage(pLingCmnInfo)) {
        return ET9STATUS_NONE;
    }

    if (bIsTerminalSpaceKey) {

        ET9AWPrivWordInfo sLookedUpWord;
        ET9STATUS wStatus;
        const ET9UINT nTotalTermPuncts = _ET9_GetNumTermPunct(pLingInfo, dwLdbNum);

        _InitPrivWordInfo(&sLookedUpWord);

        /* Common attributes */

        sLookedUpWord.Body.bWordSrc = ET9WORDSRC_GDB;

        if (bIsSecondLanguageActive) {
            sLookedUpWord.Body.bLangIndexScoring = ET9AWSECOND_LANGUAGE;
        }
        else {
            sLookedUpWord.Body.bLangIndexScoring = ET9AWFIRST_LANGUAGE;
        }

        {
            /* Single letter to space */

            ET9UINT nSingleCharWordsIndex;
            const ET9UINT nTotalSingleCharWords = _ET9_GetNumSingleCharWords(pLingInfo, dwLdbNum);

            sLookedUpWord.Base.wWordLen = ET9AWGDB_SINGLE_CHAR_SPACE_GESTURE_LEN;
            sLookedUpWord.Body.xWordFreq = ((ET9FREQPART)ET9_DB_MAX_FREQ/5)*4;

            /* Try all single char words */

            for (nSingleCharWordsIndex = 0; nSingleCharWordsIndex < nTotalSingleCharWords; ++nSingleCharWordsIndex) {

                /* Char-Space */

                ET9U32 dwIndex;
                ET9U8 bExact;
                ET9U8 bLowercase;

                sLookedUpWord.Base.sWord[0] = _ET9_GetSingleCharWord(pLingInfo, dwLdbNum, nSingleCharWordsIndex);
                sLookedUpWord.Base.sWord[1] = (ET9SYMB)0x0020;

                sLookedUpWord.Body.wGestureReturnVal = 0;
                sLookedUpWord.Body.bIsInternalGesture = 1;
                sLookedUpWord.Base.bShouldAutoAccept = 1;

                sLookedUpWord.Base.bLangIndex = 0xcc;

                wStatus = _ET9AWLdbFindEntry(pLingInfo, dwLdbNum, 0, sLookedUpWord.Base.sWord, sLookedUpWord.Base.wWordLen - 1, &dwIndex, &bExact, &bLowercase);

                if (wStatus == ET9STATUS_WORD_EXISTS) {

                    sLookedUpWord.Body.dwWordIndex = dwIndex + 1;
                    sLookedUpWord.Body.xWordFreq = (ET9FREQPART)((ET9FREQPART)ET9_DB_MAX_FREQ / (dwIndex + 1));
                }
                else {
                    sLookedUpWord.Body.dwWordIndex = 0;
                    sLookedUpWord.Body.xWordFreq = ((ET9FREQPART)ET9_DB_MAX_FREQ/5)*4;
                }

                /* Attempt to add */

                wStatus = _ET9AWSelLstWordSearch(pLingInfo, &sLookedUpWord, wIndex, wLength, bFreqIndicator);

                if (wStatus) {
                    return wStatus;
                }
            }
        }

        {
            /* Punct with space */

            ET9UINT nPunctIndex;

            /* Try all term puncts */

            sLookedUpWord.Body.xWordFreq = ((ET9FREQPART)ET9_DB_MAX_FREQ/5)*4;
            sLookedUpWord.Body.dwWordIndex = 0;

            for (nPunctIndex = 0; nPunctIndex < nTotalTermPuncts; ++nPunctIndex) {

                /* Punct-Space */

                sLookedUpWord.Base.sWord[0] = _ET9_GetTermPunctChar(pLingInfo, dwLdbNum, nPunctIndex);
                sLookedUpWord.Base.sWord[1] = (ET9SYMB) 0x0020;

                sLookedUpWord.Base.wWordLen = ET9AWGDB_PUNCT_SPACE_GESTURE_LEN;

                sLookedUpWord.Body.wGestureReturnVal = 0;
                sLookedUpWord.Body.bIsInternalGesture = 1;
                sLookedUpWord.Base.bShouldAutoAccept = 1;

                sLookedUpWord.Body.xWordFreq = (ET9FREQPART)(nTotalTermPuncts - nPunctIndex);

                sLookedUpWord.Base.bLangIndex = 0xcc;

                /* Attempt to add */

                wStatus = _ET9AWSelLstWordSearch(pLingInfo, &sLookedUpWord, wIndex, wLength, bFreqIndicator);

                if (wStatus) {
                    return wStatus;
                }

                if (bIsInitialSpaceKey) {

                    /* Space-Punct-Space */

                    sLookedUpWord.Base.sWord[2] = (ET9SYMB) 0x0020;
                    sLookedUpWord.Base.sWord[1] = sLookedUpWord.Base.sWord[0];

                    if (_ET9_LanguageSpecific_IsNonBreakingSpaceLanguage(pLingCmnInfo)) {
                        sLookedUpWord.Base.sWord[0] = (ET9SYMB) 0x00A0;
                    }
                    else {
                        sLookedUpWord.Base.sWord[0] = (ET9SYMB) 0x0020;
                    }

                    sLookedUpWord.Base.wWordLen = ET9AWGDB_SPACE_PUNCT_SPACE_GESTURE_LEN;

                    sLookedUpWord.Base.bLangIndex = 0xcc;

                    /* Attempt to add */

                    wStatus = _ET9AWSelLstWordSearch(pLingInfo, &sLookedUpWord, wIndex, wLength, bFreqIndicator);

                    if (wStatus) {
                        return wStatus;
                    }
                }
            }
        }
    }

    return ET9STATUS_NONE;
}

/*---------------------------------------------------------------------------*/
/*  -IDR-    
 *                                           
 *
 *                                                                
 *                                                                   
 *                                                   
 *                                                                    
 *
 *                                                                    
 */

static ET9STATUS ET9LOCALCALL __ET9AWGDBCustomGestureSearch(ET9AWLingInfo * const       pLingInfo,
                                                            const ET9U16                 wIndex,
                                                            const ET9U16                 wLength,
                                                            const ET9_FREQ_DESIGNATION   bFreqIndicator)
{
    ET9AWLingCmnInfo * const pLingCmnInfo = pLingInfo->pLingCmnInfo;
    ET9AWGDBInfo ET9FARDATA * const pGDB = pLingCmnInfo->pGDBInfo;

    const ET9U32 dwLdbNum = pLingCmnInfo->dwLdbNum;
    const ET9BOOL bIsSecondLanguageActive = (dwLdbNum == pLingCmnInfo->dwSecondLdbNum ? 1 : 0);

    ET9STATUS wStatus;
    ET9AWPrivWordInfo sLookedUpWord;

    ET9Assert(pLingInfo);
    ET9Assert(pLingCmnInfo);

    if (!pGDB || pLingCmnInfo->Base.pWordSymbInfo->bNumSymbs < 2) {
        return ET9STATUS_NONE;
    }

    _InitPrivWordInfo(&sLookedUpWord);

    /* Common attributes */

    sLookedUpWord.Body.bWordSrc = ET9WORDSRC_GDB;

    if (bIsSecondLanguageActive) {
        sLookedUpWord.Body.bLangIndexScoring = ET9AWSECOND_LANGUAGE;
    }
    else {
        sLookedUpWord.Body.bLangIndexScoring = ET9AWFIRST_LANGUAGE;
    }

    {
        ET9UINT nGestureIndex;
        const ET9UINT nTotalGestures = (ET9UINT)pGDB->wGestureCount;
        ET9AWGDBRecord ET9FARDATA * pbNext = ET9GDBData(pGDB);

        /* Try all gestures */

        for (nGestureIndex = 0; nGestureIndex < nTotalGestures; ++nGestureIndex, ++pbNext) {

            ET9UINT nCharIndex = 0;

            /* attributes */

            sLookedUpWord.Base.bLangIndex = 0xcc;

            /* Length */

            sLookedUpWord.Base.wWordLen = pbNext->bGestureLength;

            /* Frequency designation */

            /* Return value */

            sLookedUpWord.Body.wGestureReturnVal = pbNext->wReturnValue;

            /* mark as custom */

            sLookedUpWord.Body.bIsInternalGesture = 0;
            sLookedUpWord.Base.bShouldAutoAccept = 0;

            /* Load up word */

            for (; nCharIndex < (ET9UINT)sLookedUpWord.Base.wWordLen; ++nCharIndex) {

                sLookedUpWord.Base.sWord[nCharIndex] = pbNext->psGesture[nCharIndex];
            }

            ET9Assert(ET9MAXLDBWORDSIZE >= nCharIndex);

            /* Attempt to add */

            wStatus = _ET9AWSelLstWordSearch(pLingInfo, &sLookedUpWord, wIndex, wLength, bFreqIndicator);

            if (wStatus) {
                return wStatus;
            }
        }
    }

    return ET9STATUS_NONE;
}

/*---------------------------------------------------------------------------*/
/*  -IDR-    
 *                               
 *
 *                                                                
 *                                                                   
 *                                                   
 *                                                                    
 *
 *                                                                    
 */

ET9STATUS ET9FARCALL _ET9AWGDBWordsSearch(ET9AWLingInfo        * const pLingInfo,
                                          const ET9U16                 wIndex,
                                          const ET9U16                 wLength,
                                          const ET9_FREQ_DESIGNATION   bFreqIndicator)
{
    ET9STATUS wStatus;

    ET9Assert(pLingInfo);

    /* if feature disabled */

    if (!pLingInfo->pLingCmnInfo->Private.bTraceBuild ||
        !ET9GDBENABLED(pLingInfo->pLingCmnInfo) ||
        !pLingInfo->pLingCmnInfo->Base.pWordSymbInfo->bNumSymbs) {

        return ET9STATUS_NONE;
    }

    /* Search language dependent gestures */

    wStatus = __ET9AWGDBLanguageDependentGestureSearch(pLingInfo, wIndex, wLength, bFreqIndicator);

    /* Search custom gestures */

    wStatus = __ET9AWGDBCustomGestureSearch(pLingInfo, wIndex, wLength, bFreqIndicator);

    return wStatus;
}

/*---------------------------------------------------------------------------*/
/**
 * GDB Init.
 *
 * @param pLingInfo        Pointer to ET9 information structure.
 * @param pGDBInfo         Pointer to allocated GDB buffer.
 * @param wGestureCount    Number of gestures.
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */

ET9STATUS ET9FARCALL ET9AWGDBInit(ET9AWLingInfo * const             pLingInfo,
                                  ET9AWGDBInfo ET9FARDATA * const   pGDBInfo,
                                  const ET9U16                      wGestureCount)
{
    ET9STATUS eStatus;

    eStatus = _ET9AWSys_BasicValidityCheck(pLingInfo);

    if (eStatus) {
        return eStatus;
    }

    if (!pGDBInfo) {
        return ET9STATUS_INVALID_MEMORY;
    }

    if (!wGestureCount || wGestureCount > pGDBInfo->wGestureCount) {
        return ET9STATUS_BAD_PARAM;
    }

    if (pLingInfo->pLingCmnInfo->pGDBInfo &&
        pLingInfo->pLingCmnInfo->pGDBInfo == pGDBInfo &&
        pGDBInfo->wGestureCount == wGestureCount) {

        return ET9STATUS_ALREADY_INITIALIZED;
    }

    {
        ET9AWLingCmnInfo * const pLingCmnInfo = pLingInfo->pLingCmnInfo;

        ET9UINT nGestureIndex;
        ET9AWGDBRecord ET9FARDATA * pbNext;

        /* Assure gesture lengths */

        pbNext = ET9GDBData(pGDBInfo);
        for (nGestureIndex = 0; nGestureIndex < (ET9UINT)wGestureCount; ++nGestureIndex, ++pbNext) {

            if (!pbNext->bGestureLength || pbNext->bGestureLength > ET9MAXLDBWORDSIZE || !pbNext->wReturnValue) {
                return ET9STATUS_CORRUPT_DB;
            }
        }

        pLingCmnInfo->pGDBInfo = pGDBInfo;
        pLingCmnInfo->pGDBInfo->wGestureCount = wGestureCount;

        ET9Assert(pLingCmnInfo->pGDBInfo);
    }

    return ET9STATUS_NONE;
}

/*---------------------------------------------------------------------------*/
/**
 * Set GDB to empty.
 *
 * @param pLingInfo        Pointer to ET9 information structure.
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */

ET9STATUS ET9FARCALL ET9AWGDBReset(ET9AWLingInfo * const pLingInfo)
{
    ET9STATUS eStatus;

    eStatus = _ET9AWSys_BasicValidityCheck(pLingInfo);

    if (eStatus) {
        return eStatus;
    }

    if (!pLingInfo->pLingCmnInfo->pGDBInfo) {
        return ET9STATUS_NO_GDB;
    }

    pLingInfo->pLingCmnInfo->pGDBInfo = NULL;

    return ET9STATUS_NONE;
}

#endif /* ET9_ALPHABETIC_MODULE */
/*! @} */
/* ----------------------------------< eof >--------------------------------- */
