/*******************************************************************************
;*******************************************************************************
;**                                                                           **
;**                    COPYRIGHT 1998-2010 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: et9ahwr.c                                                   **
;**                                                                           **
;**  Description: Handwriting input processing                 .              **
;**                                                                           **
;*******************************************************************************
;******************************************************************************/

/*! \addtogroup et9hwr Handwriting input for alphabetic
* Handwriting input module for alphabetic XT9.
* @{
*/

#include "et9api.h"
#ifdef ET9_ALPHABETIC_MODULE
#ifdef ET9_HANDWRITING_MODULE
#include "et9ahwr.h"
#endif
#include "et9imu.h"
#include "et9amisc.h"
#include "et9sym.h"
#include "et9kbdef.h"

#ifdef ET9_HANDWRITING_MODULE

#define MAX_MODELS 0

static const ET9_HWR_LanguageTable sHWRLangTable[] = {
    {ET9PLIDEnglish, ARTHWR_LANG_ENGLISH},
    {ET9PLIDFrench, ARTHWR_LANG_FRENCH},
    {ET9PLIDGerman, ARTHWR_LANG_GERMAN},
    {ET9PLIDItalian, ARTHWR_LANG_ITALIAN},
    {ET9PLIDPortuguese, ARTHWR_LANG_PORTUGUESE},
    {ET9PLIDSpanish, ARTHWR_LANG_SPANISH},
    {ET9PLIDDutch, ARTHWR_LANG_DUTCH},
    {ET9PLIDFinnish, ARTHWR_LANG_FINNISH},
    {ET9PLIDDanish, ARTHWR_LANG_DANISH},
    {ET9PLIDSwedish, ARTHWR_LANG_SWEDISH},
    {ET9PLIDNorwegian, ARTHWR_LANG_NORWEGIAN},
    {ET9PLIDPolish, ARTHWR_LANG_POLISH},
    {ET9PLIDHungarian, ARTHWR_LANG_HUNGARIAN},
    {ET9PLIDCzech, ARTHWR_LANG_CZECH},
    {ET9PLIDSlovak, ARTHWR_LANG_SLOVAK},
    {ET9PLIDLatvian, ARTHWR_LANG_LATVIAN},
    {ET9PLIDLithuanian, ARTHWR_LANG_LITHUANIAN},
    {ET9PLIDIcelandic, ARTHWR_LANG_ICELANDIC},
    {ET9PLIDTurkish, ARTHWR_LANG_TURKISH},
    {ET9PLIDCroatian , ARTHWR_LANG_CROATIAN},
    {ET9PLIDSlovenian, ARTHWR_LANG_SLOVENE},
    {ET9PLIDEstonian, ARTHWR_LANG_ESTONIAN},
    {ET9PLIDRomanian, ARTHWR_LANG_ROMANIAN},
    {ET9PLIDSerbian, ARTHWR_LANG_SERBIAN},
    {ET9PLIDRussian, ARTHWR_LANG_RUSSIAN},
    {ET9PLIDBulgarian, ARTHWR_LANG_BULGARIAN},
    {ET9PLIDUkrainian, ARTHWR_LANG_UKRAINIAN},
    {ET9PLIDKazakh, ARTHWR_LANG_KAZAKH},
    {ET9PLIDGreek, ARTHWR_LANG_GREEK},
    {ET9PLIDMacedonian, ARTHWR_LANG_MACEDONIAN},
    {ET9PLIDIrish, ARTHWR_LANG_IRISH},
    {ET9PLIDNone, 0}};


/*---------------------------------------------------------------------------*/
/* -IDR- */

static ET9STATUS ET9LOCALCALL __ET9AWHwr_BasicValidityCheck(ET9AWHwrInfo *pHwrInfo, ET9U8 bLangCheck)
{
    ET9STATUS wStatus = ET9STATUS_NONE;

    if (pHwrInfo == NULL) {
        wStatus = ET9STATUS_INVALID_MEMORY;
    }
    else if (pHwrInfo->Private.wInfoInitOK != ET9GOODSETUP) {
        wStatus = ET9STATUS_NO_INIT;
    }
    else if (bLangCheck && pHwrInfo->Private.wHDBInitOK != ET9GOODSETUP) {
        wStatus = ET9STATUS_NO_DB_INIT;
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * Init HWR info.
 * This function initializes the handwriting input module.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param wLangNum                  Language number.
 * @param pHwrDatabase              Pointer to handwriting database.
 * @param pHwrWorkBuf               Pointer to work buffer.
 * @param wWorkBufSize              Size of the work buffer.
 * @param ET9AWHandle_HWR_Request   Pointer to integration layer callback function.
 * @param pPublicExtension          A value the integration layer can set and then retrieve in pHwrInfo->pPublicExtension.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_Init(ET9AWHwrInfo * const             pHwrInfo,
                                   const ET9U16                     wLangNum,
                                   ET9U8 * const                    pHwrDatabase,
                                   ET9U8 * const                    pHwrWorkBuf,
                                   const ET9U16                     wWorkBufSize,
                                   const ET9HWRREQUESTCALLBACK      ET9AWHandle_HWR_Request,
                                   void * const                     pPublicExtension)
{
    /* Maximum number of training models */
    ET9U32            dwBufSize;
    ART_RETURN_STATUS ret;
    ET9STATUS         wStatus = ET9STATUS_NONE;

    if (pHwrInfo == NULL || pHwrDatabase == NULL ||
        pHwrWorkBuf == NULL || ET9AWHandle_HWR_Request == NULL) {
        wStatus = ET9STATUS_INVALID_MEMORY;
    }
    else {
        _ET9ClearMem((ET9U8 *)pHwrInfo, (ET9UINT)(sizeof(ET9AWHwrInfo)));
        pHwrInfo->pPublicExtension = NULL;

        dwBufSize = ARTHWRGetRamSize(MAX_MODELS);
        if (!dwBufSize || (dwBufSize > (ET9U32)wWorkBufSize)) {
            wStatus = ET9STATUS_NO_MEMORY;
        }
        else {
            pHwrInfo->ET9AWHandle_HWR_Request = ET9AWHandle_HWR_Request;
            pHwrInfo->pPublicExtension = pPublicExtension;
            pHwrInfo->Private.art_hwrdate.pHwr = (void *)pHwrWorkBuf;
            pHwrInfo->Private.art_hwrdate.iHwrLen = (DWORD)wWorkBufSize;
            pHwrInfo->Private.art_hwrdate.pInternalLanguageDict = (char*)pHwrDatabase;

            ret = ARTHWRInit(&pHwrInfo->Private.art_hwrdate, MAX_MODELS);
            if (ret != ART_STATUS_OK) {
                if (ret == ART_STATUS_NO_ENOUGH_RAM) {
                    wStatus = ET9STATUS_NO_MEMORY;
                }
                else if (ret == ART_STATUS_INVALID_DICT) {
                    wStatus = ET9STATUS_CORRUPT_DB;
                }
                else {
                    wStatus = ET9STATUS_NO_INIT;
                }
            }
        }
    }
    if (!wStatus) {
        pHwrInfo->Private.wInfoInitOK = ET9GOODSETUP;
        /* Set language  */
        wStatus = ET9AWHwr_SetLanguage(pHwrInfo, wLangNum);
        if (!wStatus) {
            wStatus = ET9AWHwr_SetRecognitionMode(pHwrInfo, ET9AW_HWR_LOWER);
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * Set character recognizer pad size.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param minX                      Upper left hand corner coordinates.
 * @param minY                      Upper left hand corner coordinates.
 * @param maxX                      Lower right hand corner coordinates.
 * @param maxY                      Lower right hand corner coordinates.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_SetPadSize(ET9AWHwrInfo * const   pHwrInfo,
                                         const ET9UINT          minX,
                                         const ET9UINT          minY,
                                         const ET9UINT          maxX,
                                         const ET9UINT          maxY)
{
    ET9STATUS           wStatus;
    ART_WritingAreaInfo wai;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 0)) == ET9STATUS_NONE) {
        wai.maxX = (ET9U16)maxX;
        wai.maxY = (ET9U16)maxY;
        wai.minX = (ET9U16)minX;
        wai.minY = (ET9U16)minY;

        if (ARTHWRSetInputBoxSize(&pHwrInfo->Private.art_hwrdate,  wai) != ART_STATUS_OK) {
            wStatus = ET9STATUS_BAD_PARAM;
        }
        else {
            _ET9ByteCopy((ET9U8 *)&pHwrInfo->wai, (ET9U8 *)&wai, sizeof(ART_WritingAreaInfo));
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * Set character recognition mode.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param eMode                     Mode to set (alpha lower/upper, punct or numeric).
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_SetRecognitionMode(ET9AWHwrInfo * const   pHwrInfo,
                                                 const ET9AW_HWR_MODE   eMode)
{

    ET9STATUS           wStatus;
    ART_RecognitionMode recMode = (ART_RecognitionMode)0;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK) {
            wStatus = ET9STATUS_NO_MODE_CHANGE_WITH_PEN_DOWN;
        }
        else {
            switch (eMode) {
            case ET9AW_HWR_LOWER:
                recMode = ELowerMode;
                break;
            case ET9AW_HWR_UPPER:
                recMode = EUpperMode;
                break;
            case ET9AW_HWR_NUMERIC:
                recMode = ENumericMode;
                break;
            case ET9AW_HWR_PUNCT:
                recMode = EPuncMode;
                break;
            default:
                wStatus = ET9STATUS_BAD_PARAM;
                break;
            }
            if (!wStatus) {
                pHwrInfo->eRecogMode = eMode;
                /* Set recognition mode  */
                if (ARTHWRSetRecognitionMode(&pHwrInfo->Private.art_hwrdate, recMode) != ART_STATUS_OK) {
                    wStatus = ET9STATUS_NO_INIT;
                }
            }
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/* -IDR- */

static ET9U8 ET9LOCALCALL __ET9GetHWRLanguageSetting(ET9U16 wLangNum, ET9U32 *dwLang)
{
    const ET9_HWR_LanguageTable *pEntry = sHWRLangTable;

    ET9Assert(dwLang);

    wLangNum &= ET9PLIDMASK;
    while (pEntry->wLanguage != ET9PLIDNone) {
        if (wLangNum == pEntry->wLanguage) {
            *dwLang = pEntry->dwHWRSetting;
            return 0;
        }
        pEntry++;
    }
    return 1;
}


/*---------------------------------------------------------------------------*/
/**
 * Set language.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param wLangNum                  Language ID.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_SetLanguage(ET9AWHwrInfo * const  pHwrInfo,
                                          const ET9U16          wLangNum)
{
    ET9STATUS wStatus;
    ET9U32    dwLang = 0;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 0)) == ET9STATUS_NONE) {
        pHwrInfo->Private.wHDBInitOK = 0;
        if (pHwrInfo->dwStateBits & (ET9AW_HWR_PEN_DOWN_MASK | ET9AW_HWR_PEN_UP_MASK)) {
            pHwrInfo->dwStateBits &= ~(ET9AW_HWR_PEN_DOWN_MASK | ET9AW_HWR_PEN_UP_MASK);
            pHwrInfo->Private.wSavedRecogSymCount = pHwrInfo->Private.wRecogSymCount = 0;
            ARTHWRResetData(&pHwrInfo->Private.art_hwrdate);
        }
        if (__ET9GetHWRLanguageSetting(wLangNum, &dwLang)) {
            wStatus = ET9STATUS_BAD_PARAM;
        }
        else {
            pHwrInfo->wLangID = wLangNum;
            if (ARTHWRSetLanguage(&pHwrInfo->Private.art_hwrdate, dwLang) != ART_STATUS_OK) {
                wStatus = ET9STATUS_NO_DB_INIT;
            }
            else {
                pHwrInfo->Private.wHDBInitOK = ET9GOODSETUP;
            }
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * This function gets the current HWR language setting.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pwLdbNum                  Pointer to return LDB number.
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */

ET9STATUS ET9FARCALL ET9AWHwr_GetLanguage(ET9AWHwrInfo * const  pHwrInfo,
                                          ET9U16 * const        pwLdbNum)
{
    ET9STATUS wStatus;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pwLdbNum == NULL) {
            wStatus = ET9STATUS_INVALID_MEMORY;
        }
        else {
            *pwLdbNum = pHwrInfo->wLangID;
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/* -IDR- */

static ET9STATUS ET9LOCALCALL __ET9RequestHWRTimeout(ET9AWHwrInfo *pHwrInfo,
                                                     ET9AW_HWR_TMR eType)
{
    ET9AW_HWR_Request sRequest;

    ET9Assert(pHwrInfo != NULL);

    sRequest.eType = ET9AW_HWR_REQ_TIMEOUT;
    sRequest.data.sTimeout.eTimerType = eType;
    sRequest.data.sTimeout.nTimerID   = (ET9INT)(eType);
    return pHwrInfo->ET9AWHandle_HWR_Request(pHwrInfo, &sRequest);
}


/*---------------------------------------------------------------------------*/
/**
 * Add point to recognizer.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pointX                    Coordinates of added point.
 * @param pointY                    Coordinates of added point.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_AddPoint(ET9AWHwrInfo * const     pHwrInfo,
                                       const ET9UINT            pointX,
                                       const ET9UINT            pointY)
{
    ET9STATUS wStatus;
    ART_Point point;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (!(pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK)) {
            wStatus = ET9STATUS_NO_PEN_DOWN_REPORTED;
        }
        else {
            if ((pointX < pHwrInfo->wai.minX) || (pointX > pHwrInfo->wai.maxX) ||
                (pointY < pHwrInfo->wai.minY) || (pointY > pHwrInfo->wai.maxY)) {
                wStatus = ET9STATUS_INVALID_POINT;
            }
            point.x = (short) pointX;
            point.y = (short) pointY;

            if (ARTHWRAddPoint(&pHwrInfo->Private.art_hwrdate, point) != ART_STATUS_OK) {
                wStatus = ET9STATUS_ERROR;
            }
            else {
                /* RESTART EVENT TIMER */
                __ET9RequestHWRTimeout(pHwrInfo, ET9AW_HWR_TMR_EVENT);
            }
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * Handle pen down.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pointX                    Coordinates of added point.
 * @param pointY                    Coordinates of added point.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_HandlePenDown(ET9AWHwrInfo * const    pHwrInfo,
                                            const ET9UINT           pointX,
                                            const ET9UINT           pointY)
{
    ET9STATUS wStatus;
    ART_Point point;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK) {
            wStatus = ET9STATUS_PEN_ALREADY_DOWN;
        }
        else {
            if ((pointX < pHwrInfo->wai.minX) || (pointX > pHwrInfo->wai.maxX) ||
                (pointY < pHwrInfo->wai.minY) || (pointY > pHwrInfo->wai.maxY)) {
                wStatus = ET9STATUS_INVALID_POINT;
            }
            point.x = (ET9S16)pointX;
            point.y = (ET9S16)pointY;

            if (ARTHWRAddPoint(&pHwrInfo->Private.art_hwrdate, point) != ART_STATUS_OK) {
                wStatus = ET9STATUS_ERROR;
            }
            else {
                pHwrInfo->dwStateBits &= ~(ET9AW_HWR_PEN_UP_MASK);
                pHwrInfo->dwStateBits |= ET9AW_HWR_PEN_DOWN_MASK;
                __ET9RequestHWRTimeout(pHwrInfo, ET9AW_HWR_TMR_EVENT);
            }
        }
    }
    return wStatus;
}

/*---------------------------------------------------------------------------*/
/* -IDR- */

static ET9STATUS ET9LOCALCALL __ProcessRecognizedSymbols(ET9AWHwrInfo      *pHwrInfo,
                                                         ART_RecResults    *pRecRes,
                                                         ET9WordSymbInfo   *pWordSymbInfo,
                                                         ET9U8              bCurrIndexInList,
                                                         ET9SYMB           *psFunctionKey)
{
    ET9STATUS wStatus = ET9STATUS_NONE;
    ART_RecNBest *holder;
    ART_RecResult *holder2;
    ET9INT        i, j, k;
    ET9SymbInfo       *pSymbInfo;
    ET9SYMB   sNBestSymbs[MAX_N_BEST];
    ET9U8          nScore[MAX_N_BEST];
    ET9INPUTSHIFTSTATE eShiftState;
    ET9U8     bFunction = 0;
    ET9AWHwrNBestSym  *psCurSym;
    ET9S16             nMaxProb = 0;

    ET9Assert(pHwrInfo != NULL);
    ET9Assert(pRecRes);
    ET9Assert(pWordSymbInfo != NULL);
    ET9Assert(psFunctionKey);

    holder = pRecRes->Res;
    for (i = 0; i < pRecRes->NumRes && pHwrInfo->Private.wRecogSymCount < ET9AW_HWR_RETAINED_SYMS; ++i, ++holder) {
        holder2 = holder->Res;
        psCurSym = &pHwrInfo->Private.sRecogSyms[pHwrInfo->Private.wRecogSymCount];
        psCurSym->wAltSymCount = (ET9U16)holder->NumRes;
        for (j = 0, k = 0; j < holder->NumRes; ++j, ++holder2) {
            switch (holder2->Code) {
            /* have no idea why this value is sometimes getting returned... */
            case 0x17:
                --psCurSym->wAltSymCount;
                break;
            case CODE_CR_GESTURE:
            case CODE_SPACE_GESTURE:
            case CODE_TAB_GESTURE:
                if (j == 0) {
                    /* if gesture is top recognition, stop there */
                    psCurSym->wAltSymCount = 1;
                    psCurSym->sSyms[0] = holder2->Code;
                    /* force end to loop */
                    j = holder->NumRes;
                    bFunction = 1;
                }
                else {
                    /* just ignore gesture if not primary recognition */
                    --psCurSym->wAltSymCount;
                }
                break;
            case CODE_BACKSPACE_GESTURE:
                /* if there are previously recognized symbols */
                if (j == 0) {
                    if (pHwrInfo->Private.wRecogSymCount) {
                        /* delete the last one */
                        --pHwrInfo->Private.wRecogSymCount;
                        /* if that deleted symbol already processed... */
                        if (pHwrInfo->Private.wRecogSymCount < pHwrInfo->Private.wSavedRecogSymCount) {
                            /* move backwards by deleting it from WordSymbInfo */
                            pHwrInfo->Private.wSavedRecogSymCount = pHwrInfo->Private.wRecogSymCount;
                            if (pWordSymbInfo->bNumSymbs) {
                                pSymbInfo = &pWordSymbInfo->SymbsInfo[pWordSymbInfo->bNumSymbs - 1];
                                if (pSymbInfo->eShiftState == ET9SHIFT) {
                                    ET9AWHwr_SetShift(pHwrInfo, pWordSymbInfo);
                                }
                                ET9ClearOneSymb(pWordSymbInfo);
                                bCurrIndexInList = ET9_NO_ACTIVE_INDEX;
                            }
                        }
                        /* do this to prevent increment of wRecogSymCount */
                        psCurSym->wAltSymCount = 0;
                    }
                    else {
                        /* if gesture is top recognition, stop there */
                        psCurSym->wAltSymCount = 1;
                        psCurSym->sSyms[0] = holder2->Code;
                        bFunction = 1;
                    }
                    /* force end to loop */
                    j = holder->NumRes;
                }
                else {
                    /* just ignore gesture if not primary recognition */
                    --psCurSym->wAltSymCount;
                }
                break;
            default:
                psCurSym->sSyms[k] = holder2->Code;
                psCurSym->nSymScores[k++] = holder2->Score;
                if (holder2->Score > nMaxProb) {
                    nMaxProb = holder2->Score;
                }
                break;
            }
        }
        if (psCurSym->wAltSymCount) {
            ++pHwrInfo->Private.wRecogSymCount;
        }
    }
    /* Now process all saved sym/function info for current sym entry */
    /* start from the LAST SAVED POSITION (to prevent duplication)   */
    /* if a function gesture is detected, go ahead and finish up the */
    /* stroke processing                                             */
    if (pHwrInfo->Private.wRecogSymCount > pHwrInfo->Private.wSavedRecogSymCount) {
        for (i = pHwrInfo->Private.wSavedRecogSymCount; i < pHwrInfo->Private.wRecogSymCount; ++i) {
            /* if only one sym/gesture recognized, treat as explicit */
            psCurSym = &pHwrInfo->Private.sRecogSyms[i];
            if (bFunction) {
                switch (psCurSym->sSyms[0]) {
                case CODE_BACKSPACE_GESTURE:
                    /* only process if it is the only symbol collected */
                    /* NOTE: Getting weird returns indicating backspace */
                    /* with no prior syms  */
                    *psFunctionKey = ET9KEY_BACK;
                    /* shut off shift bit */
                    if (!ET9CAPS_MODE(pWordSymbInfo->dwStateBits)) {
                        ET9AWHwr_SetUnShift(pHwrInfo, pWordSymbInfo);
                    }
                    break;
                case CODE_CR_GESTURE:
                    *psFunctionKey = ET9KEY_RETURN;
                    break;
                case CODE_SPACE_GESTURE:
                case CODE_TAB_GESTURE:
                    *psFunctionKey = ET9KEY_SPACE;
                    break;
                default:
                    break;
                }
            }
            /* else, sym will be added as 'custom symbol set */
            else {
                /* Adding explicit entry code here */
                if (i == pHwrInfo->Private.wSavedRecogSymCount) {
                    _ET9ImminentSymb(pWordSymbInfo, bCurrIndexInList, 0);
                }
                if (pWordSymbInfo->bNumSymbs < ET9MAXWORDSIZE) {
                    for (j = 0; j < psCurSym->wAltSymCount; ++j) {
                        sNBestSymbs[j] = psCurSym->sSyms[j];
                        nScore[j] = (ET9U8)((psCurSym->nSymScores[j] * 255) / nMaxProb);
                        if (!nScore[j]) {
                            nScore[j] = 1;
                        }
                    }
                    if (ET9SHIFT_MODE(pWordSymbInfo->dwStateBits)) {
                        eShiftState = ET9SHIFT;
                    }
                    else if (ET9CAPS_MODE(pWordSymbInfo->dwStateBits)) {
                        eShiftState = ET9CAPSLOCK;
                    }
                    else {
                        eShiftState = ET9NOSHIFT;
                    }

                    ET9AddCustomSymbolSet(pWordSymbInfo,
                                        sNBestSymbs,
                                        nScore,
                                        psCurSym->wAltSymCount,
                                        eShiftState,
                                        bCurrIndexInList);
                    /* shut off shift bit (for first sym entered) */
                    if (!ET9CAPS_MODE(pWordSymbInfo->dwStateBits)) {
                        ET9AWHwr_SetUnShift(pHwrInfo, pWordSymbInfo);
                    }
                }
                else {
                    wStatus = ET9STATUS_FULL;
                    /* force loop to end */
                    i = pHwrInfo->Private.wRecogSymCount;
                }
            }
            /* if function detected, stop processing */
            if (*psFunctionKey) {
                i = pHwrInfo->Private.wRecogSymCount;
            }
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * Handle pen up.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pWordSymbInfo             Pointer to overall word construction struct.
 * @param bCurrIndexInList          Index of currently highlighted word in sellist.
 * @param psFunctionKey             Pointer to place to return detected function key in.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_HandlePenUp(ET9AWHwrInfo          * const pHwrInfo,
                                          ET9WordSymbInfo       * const pWordSymbInfo,
                                          const ET9U8                   bCurrIndexInList,
                                          ET9SYMB               * const psFunctionKey)
{
    ET9STATUS         wStatus;
    ART_RETURN_STATUS ret;
    ART_RecResults    RecRes;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pWordSymbInfo == NULL || psFunctionKey == NULL || pWordSymbInfo->wInitOK != ET9GOODSETUP) {
            wStatus = ET9STATUS_INVALID_MEMORY;
        }
        else if (pHwrInfo->dwStateBits & ET9AW_HWR_PEN_UP_MASK) {
            wStatus = ET9STATUS_PEN_UP_ALREADY_REPORTED;
        }
        else if (!(pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK)) {
            wStatus = ET9STATUS_NO_PEN_DOWN_REPORTED;
        }
        else {
            /* Clear 'Pen Down' state */
            pHwrInfo->dwStateBits &= ~(ET9AW_HWR_PEN_DOWN_MASK);
            *psFunctionKey = 0;
            ret = ARTHWREndOfStroke(&pHwrInfo->Private.art_hwrdate, &RecRes);

            /* only process if return status indicates results exist */
            if ((ret == ART_STATUS_FINAL_RESULTS) ||
                (ret == ART_STATUS_INCOMPLETE_RESULTS)) {

                wStatus = __ProcessRecognizedSymbols(pHwrInfo, &RecRes, pWordSymbInfo,
                                              bCurrIndexInList, psFunctionKey);
            }
            /* else if obvious error processing */
            else if (ret == ART_STATUS_UNKNOWN) {
                wStatus = ET9STATUS_ERROR;
            }
            /* if not a function gesture, set timer (user may have more strokes */
            /* to enter for the current character)                              */
            if (!(*psFunctionKey)) {
                /* save the last processed position */
                pHwrInfo->Private.wSavedRecogSymCount = pHwrInfo->Private.wRecogSymCount;
                pHwrInfo->dwStateBits |= ET9AW_HWR_PEN_UP_MASK;
                __ET9RequestHWRTimeout(pHwrInfo, ET9AW_HWR_TMR_PENUP);
            }
            /* otherwise wrap up the current symbol's stroke processing */
            else {
                pHwrInfo->Private.wSavedRecogSymCount = pHwrInfo->Private.wRecogSymCount = 0;
                ret = ARTHWRResetData(&pHwrInfo->Private.art_hwrdate);
                if (ret == ART_STATUS_UNKNOWN) {
                    wStatus = ET9STATUS_NO_INIT;
                }
            }
        }
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * This function sets lower case.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pWordSymbInfo             Pointer to overall word construction struct.
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */

ET9STATUS ET9FARCALL ET9AWHwr_SetUnShift(ET9AWHwrInfo       * const pHwrInfo,
                                         ET9WordSymbInfo    * const pWordSymbInfo)
{
    ET9STATUS wStatus;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pWordSymbInfo == NULL || pWordSymbInfo->wInitOK != ET9GOODSETUP) {
            wStatus = ET9STATUS_INVALID_MEMORY;
        }
        else if (pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK) {
            wStatus = ET9STATUS_NO_MODE_CHANGE_WITH_PEN_DOWN;
        }
        else {
#ifdef ET9_KDB_MODULE
            ET9SetUnShift(pWordSymbInfo);
#endif
            if (pHwrInfo->eRecogMode == ET9AW_HWR_UPPER) {
                wStatus = ET9AWHwr_SetRecognitionMode(pHwrInfo, ET9AW_HWR_LOWER);
            }
        }

    }
    else {
#ifdef ET9_KDB_MODULE
        wStatus = ET9SetUnShift(pWordSymbInfo);
#endif
     }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * This function sets shift.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pWordSymbInfo             Pointer to overall word construction struct.
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */

ET9STATUS ET9FARCALL ET9AWHwr_SetShift(ET9AWHwrInfo         * const pHwrInfo,
                                       ET9WordSymbInfo      * const pWordSymbInfo)
{
    ET9STATUS wStatus;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pWordSymbInfo == NULL || pWordSymbInfo->wInitOK != ET9GOODSETUP) {
            wStatus = ET9STATUS_INVALID_MEMORY;
        }
        else if (pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK) {
            wStatus = ET9STATUS_NO_MODE_CHANGE_WITH_PEN_DOWN;
        }
        else {
#ifdef ET9_KDB_MODULE
            ET9SetShift(pWordSymbInfo);
#endif
            if (pHwrInfo->eRecogMode == ET9AW_HWR_LOWER) {
                wStatus = ET9AWHwr_SetRecognitionMode(pHwrInfo, ET9AW_HWR_UPPER);
            }
        }
    }
    else {
#ifdef ET9_KDB_MODULE
        wStatus = ET9SetShift(pWordSymbInfo);
#endif
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * This function sets caps lock.
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pWordSymbInfo             Pointer to overall word construction struct.
 *
 * @return ET9STATUS_NONE on success, otherwise return ET9 error code.
 */

ET9STATUS ET9FARCALL ET9AWHwr_SetCapsLock(ET9AWHwrInfo          * const pHwrInfo,
                                          ET9WordSymbInfo       * const pWordSymbInfo)
{
    ET9STATUS wStatus;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pWordSymbInfo == NULL || pWordSymbInfo->wInitOK != ET9GOODSETUP) {
            wStatus = ET9STATUS_INVALID_MEMORY;
        }
        else if (pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK) {
            wStatus = ET9STATUS_NO_MODE_CHANGE_WITH_PEN_DOWN;
        }
        else {
#ifdef ET9_KDB_MODULE
            ET9SetCapsLock(pWordSymbInfo);
#endif
            if (pHwrInfo->eRecogMode == ET9AW_HWR_LOWER) {
                wStatus = ET9AWHwr_SetRecognitionMode(pHwrInfo, ET9AW_HWR_UPPER);
            }
        }
    }
    else {
#ifdef ET9_KDB_MODULE
        wStatus = ET9SetCapsLock(pWordSymbInfo);
#endif
    }
    return wStatus;
}


/*---------------------------------------------------------------------------*/
/**
 * handle time out (complete stroke interpretation).
 *
 * @param pHwrInfo                  Pointer to handwriting information structure.
 * @param pWordSymbInfo             Pointer to overall word construction struct.
 * @param nTimerID                  Timer ID associated with timer that expired.
 * @param bCurrIndexInList          Index of currently highlighted word in sellist.
 * @param psFunctionKey             Pointer to place to return detected function key in.
 *
 * @return ET9STATUS from call.
 */

ET9STATUS ET9FARCALL ET9AWHwr_ProcessStrokes(ET9AWHwrInfo       * const pHwrInfo,
                                             ET9WordSymbInfo    * const pWordSymbInfo,
                                             const ET9INT               nTimerID,
                                             const ET9U8                bCurrIndexInList,
                                             ET9SYMB            * const psFunctionKey)
{
    ET9STATUS         wStatus;
    ART_RETURN_STATUS ret;
    ART_RecResults    RecRes;
    ET9U8             bUnexpected = 0;

    if ((wStatus = __ET9AWHwr_BasicValidityCheck(pHwrInfo, 1)) == ET9STATUS_NONE) {
        if (pWordSymbInfo == NULL || psFunctionKey == NULL || pWordSymbInfo->wInitOK != ET9GOODSETUP) {
            wStatus = ET9STATUS_INVALID_MEMORY;
        }
        else {
            /* make sure set to 0 if no function gesture detected */
            *psFunctionKey = 0;

            /* if currently idle, timer doesn't do anything */
            if (pHwrInfo->dwStateBits & (ET9AW_HWR_PEN_DOWN_MASK | ET9AW_HWR_PEN_UP_MASK)) {
                if (nTimerID &&
                    ((pHwrInfo->dwStateBits & ET9AW_HWR_PEN_UP_MASK) && (nTimerID != ET9AW_HWR_TMR_PENUP)) ||
                    ((pHwrInfo->dwStateBits & ET9AW_HWR_PEN_DOWN_MASK) && (nTimerID != ET9AW_HWR_TMR_EVENT))) {
                    bUnexpected = 1;
                }

                pHwrInfo->dwStateBits &= ~(ET9AW_HWR_PEN_DOWN_MASK | ET9AW_HWR_PEN_UP_MASK);
                /* check HW engine for recognized symbols */
                ret = ARTHWRRecognizeData(&pHwrInfo->Private.art_hwrdate, &RecRes);
                if (ret == ART_STATUS_FINAL_RESULTS) {
                    wStatus = __ProcessRecognizedSymbols(pHwrInfo, &RecRes, pWordSymbInfo,
                                                      bCurrIndexInList, psFunctionKey);
                }
                pHwrInfo->Private.wSavedRecogSymCount = pHwrInfo->Private.wRecogSymCount = 0;
                ret = ARTHWRResetData(&pHwrInfo->Private.art_hwrdate);
                if (ret == ART_STATUS_UNKNOWN && !wStatus) {
                    wStatus = ET9STATUS_NO_INIT;
                }
                else if (bUnexpected && !wStatus) {
                    /* provided as informational, but still processes timeout */
                    wStatus = ET9STATUS_UNEXPECTED_TIMEOUT;
                }
            }
        }
    }
    return wStatus;
}
#endif


#endif /* ET9_ALPHABETIC_MODULE */
/*! @} */
/* ----------------------------------< eof >--------------------------------- */
