/*******************************************************************************
;*******************************************************************************
;**                                                                           **
;**                  COPYRIGHT 2001-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: et9asearchdb.c                                              **
;**                                                                           **
;**  Description: Compare a text string with a path.                          **
;**                                                                           **
;*******************************************************************************
;******************************************************************************/


/*==========================// */
/*      INCLUDE FILES       // */
/*==========================// */

#include "et9asearchdb.h"
#include "et9autilities.h"

#define __SDB_INIT_2(pV, v1, v2)                pThis->pV[0] = (v1); pThis->pV[1] = (v2)


#define SLIDER_POS_1                            (Z1_OP_CORRECT_VERTICAL_ONLY_ON_KEY_2 / 2)
/*#define SLIDER_POS_1                            100 */
/*#define SLIDER_POS_2                            ((Z1_OP_CORRECT_VERTICAL_ONLY_ON_KEY_2 + Z1_OP_CORRECT_VERTICAL_ANYWHERE) / 2) */
#define SLIDER_POS_2                            500
#define SLIDER_POS_3                            ((Z1_OP_CORRECT_VERTICAL_ANYWHERE + 1000) / 2)
#define SLIDER_POS_4                            1000
#define SLIDER_POS_COUNT                        4

#if DEBUG_SHOW_MATCH_TRACE || DEBUG_SHOW_WCW_TRACE || RUN_STARTUP_WITHOUT_DEBUG_TRACE
#define DEBUG_MGD_PT                            DEBUG_TAP
#define PERFORM_MGD_TESTS                       DEBUG_TAP
#define SHOW_FREQ_RATIO_CHANGES                 1
#if DEBUG_MGD_PT
#define PREP_DEBUG_WORD(candidate, candidateIndex, context, verb, from) PrepDebugWord(candidate, candidateIndex, context, verb, from)
#else
#define PREP_DEBUG_WORD(candidate, candidateIndex, context, verb, from)
#endif
#define PERFORM_STARTUP_TESTS                   1               /* Set PERFORM_STARTUP_TESTS to 0, or the maximum number of tests to perform */
#define PERFORM_STARTUP_TEST_1                  0
#define PERFORM_STARTUP_TEST_2                  0
#define PERFORM_STARTUP_TEST_3                  0
#define PERFORM_STARTUP_TEST_4                  0
#define PERFORM_STARTUP_TEST_5                  0
#define PERFORM_STARTUP_TEST_6                  0
#define PERFOM_ANY_TAP_TEST (PERFORM_STARTUP_TEST_1 || PERFORM_STARTUP_TEST_2 || PERFORM_STARTUP_TEST_3 || PERFORM_STARTUP_TEST_4 || PERFORM_STARTUP_TEST_5 || PERFORM_STARTUP_TEST_6)
#define PERFORM_STARTUP_TESTS_WITH_ALL_SLIDER_POSITIONS     0
#define DEFAULT_SLIDER_TEST_POSITION            SLIDER_POS_2
#define PERFORM_SWYPE_TEST1                     1
#else
#define DEBUG_MGD_PT                            0
#define PREP_DEBUG_WORD(candidate, candidateIndex, context, verb, from)
#define PERFORM_MGD_TESTS                       0
#define PERFORM_STARTUP_TESTS       0                           /* Set PERFORM_STARTUP_TESTS to 0, or the maximum number of tests to perform */
#define PERFORM_STARTUP_TESTS_WITH_ALL_SLIDER_POSITIONS     0
#define DEFAULT_SLIDER_TEST_POSITION            SLIDER_POS_3
#define PERFORM_SWYPE_TEST1                     0
#endif

#if PERFORM_STARTUP_TESTS
#define TEST_SET_PREDICTION_WORD                0
#define SUPPRESS_INTERMEDIATE_STARTUP_DUMPS     1

#define ST_ANY_POSITION     (-1)
#define ST_NO_POSITION      (-2)
#define ST_TAP_POSITION     (3)
#define ST_DEFAULT_POSITION 0

typedef struct
{
    STRACHAR    *in, *out;
    ET9BOOL        sliderPos[SLIDER_POS_COUNT];
    ET9BOOL        testVersion[2];
}
ST_KnownMiss;

/* Use this array for any words, at any slider positions, that happen to fail to get added as candidates */
/* through fix steps that aren't bugs but lead to the word being dropped. */
/* Enter 1 (true) for the slider positions where this happens. */
static const ST_KnownMiss knownMisses[] =
{
    /* Filler, in case there are no other entries */
    {"tappedchars",     "wordthatshouldappear", {0, 0, 0, 0},    {0, 0}}, /* */

    /* To investigate */
    /*{"form",            "from",                 {0, 0, 1, 1},    {1, 0}}, // */
    /*{"jsut",            "hair",                 {0, 0, 1, 1},    {0, 1}}, // */
    /*{"aslo",            "also",                 {0, 0, 1, 0},    {0, 1}}, // */
    /*{"wonr",            "wine",                 {0, 0, 0, 1},    {0, 1}}, // */
    /*{"thakns",          "tshiba",               {0, 0, 0, 1},    {0, 1}}, // */
    /*{"whirld",          "whield",               {0, 0, 0, 1},    {0, 1}}, // */
    /*{"whirld",          "whields",              {0, 0, 0, 1},    {0, 1}}, // */

    /* To fix */

    /* Accepted */
};

typedef struct
{
    const STRACHAR  *in, *out;
    SBYTE2          position;
    ET9BOOL            sliderPos[SLIDER_POS_COUNT];
}
StartupTestStrings1;

/* Sources of typos: */
/* http://msgboard.snopes.com/cgi-bin/ultimatebb.cgi?ubb=get_topic;f=95;t=000560;p=1 */

static const StartupTestStrings1 tapTest1Data[] =
{
    /* Current tests */

    /* Char 23 transposition */
#if ALLOW_CHAR_2_3_TRANSPOSITION
    {"wonr",            "won't",            ST_DEFAULT_POSITION,    {0, 0, 0, 1}},
    {"thakns",          "thanks",           ST_DEFAULT_POSITION,    {0, 0, 0, 1}},
    {"jsut",            "just",             ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"form",            "from",             ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"aslo",            "also",             ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"adn",             "and",              ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"ect",             "etc",              ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"whirld",          "whirled",          ST_ANY_POSITION,        {0, 0, 0, 1}},
    {"teh",             "the",              ST_DEFAULT_POSITION,    {0, 0, 1, 0}},
    {"teh",             "the",              ST_ANY_POSITION,        {0, 0, 1, 1}},
#endif
    /* Defaults */
    {"accuraet",        "accurate",         ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"framewrk",        "framework",        ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"framewrkk<",      "framework",        ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"alone",           "alone",            ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"all<one",         "alone",            ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"allone",          "alone",            ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"aloy",            "slot",             ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"im",              "i'm",              ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"frammework",      "framework",        ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"acurate",         "accurate",         ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"accuratee",       "accurate",         ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"accurateyl",      "accurately",       ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"gadfyl",          "gadfly",           ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"restuaratn",      "restaurant",       ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"indemniyf",       "indemnify",        ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"wonr",            "won't",            ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"compture",        "computer",         ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"clinet",          "client",           ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"researcg",        "research",         ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"thansk",          "thanks",           ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"thakns",          "thanks",           ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"definatley",      "definitely",       ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"yourkshire",      "Yorkshire",        ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"unfortunaltey",   "unfortunately",    ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"unfortunatley",   "unfortunately",    ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"alclhol",         "alcohol",          ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"probarbly",       "probably",         ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"mispellings",     "misspellings",     ST_DEFAULT_POSITION,    {0, 0, 1, 1}},
    {"fffff",           "gruff",            ST_DEFAULT_POSITION,    {0, 0, 0, 1}},
    {"fffff<<<<<fffff",
                        "gruff",            ST_DEFAULT_POSITION,    {0, 0, 0, 1}},
    {"ffffff<",
                        "gruff",            ST_DEFAULT_POSITION,    {0, 0, 0, 1}},
    {"aaaaaaaaa",       "assassins",        ST_DEFAULT_POSITION,    {0, 0, 0, 1}},

    /* 1 */
    {"buy",             "but",              1,                      {1, 1, 1, 1}},
    {"sex",             "sec",              1,                      {1, 1, 1, 1}},
    {"botson",          "Boston",           1,                      {0, 0, 1, 1}},

    /* 2 */

    /* Anys */
    {"beucase",         "because",          ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"christina",       "Christian",        ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"framewrk<",       "framework",        ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"id",              "id",               ST_ANY_POSITION,        {0, 0, 1, 1}},    /* New (not orig) code sorts "id" above "i'd" by length difference */
    {"id",              "i'd",              ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"tes",             "tea",              ST_ANY_POSITION,        {1, 1, 1, 1}},
    {"attatched",       "attached",         ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"denmarkk",        "Denmark",          ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"funnies",         "funniest",         ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"indemniy",        "indemnify",        ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"sprot",           "sport",            ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"alos",            "also",             ST_ANY_POSITION,        {0, 0, 1, 1}},
/*  {"brain",           "brian",            ST_ANY_POSITION,        {0, 0, 1, 1}}, */
    {"retards",         "regards",          ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"schhola",         "schools",          ST_ANY_POSITION,        {0, 0, 1, 1}},
/*  {"aloy",            "alloy",            ST_ANY_POSITION,        {0, 0, 0, 0}}, */
/*  {"whirld",          "whirled",          ST_ANY_POSITION,        {0, 0, 0, 1}}, */
    {"edit",            "exit",             ST_ANY_POSITION,        {0, 0, 0, 1}},

#if ALLOW_CHAR_2_3_TRANSPOSITION
    {"jsut",            "just",             ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"form",            "from",             ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"aslo",            "also",             ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"adn",             "and",              ST_ANY_POSITION,        {0, 0, 1, 1}},
    {"ect",             "etc",              ST_ANY_POSITION,        {0, 0, 1, 1}},
#endif

    /* Failures */
#if 0
    {"effect",          "affect",           ST_NO_POSITION,         {1, 1, 1, 1}},
    {"acn",             "can",              ST_NO_POSITION,         {1, 1, 1, 1}},
    {"shit",            "shift",            ST_NO_POSITION,         {1, 1, 1, 1}},
#endif
};

typedef struct
{
    STRACHAR    *in, *check, *pos;
    ET9BOOL        sliderPos[SLIDER_POS_COUNT];
}
StartupDeleteTestString;

static const StartupDeleteTestString tapTest4Data[] =
{
    /* Tapped           search for          which positions (== 1)  slider positions */
    {"good",            "good",             "1111",             {1, 1, 1, 1}},
    {"fggostly",        "ghosts",           "1111111",          {1, 1, 1, 1}},
    {"sibngle",         "single",           "111111",           {1, 1, 1, 1}},
    {"regsular",        "regular",          "11111111",         {1, 1, 1, 1}},
    {"restuaratn",      "restaurant",       "1111111111",       {1, 1, 1, 1}},
    {"framewrk",        "framework",        "111111111",        {1, 1, 1, 1}},
};

/* MGD Test strings */

/* osllistuu<i<<<<<<<sllis */

#endif /* PERFORM_STARTUP_TESTS */

#if DEBUG_LOG_MATCH_TRACE
    static ET9BOOL debugThis;
    static ET9BOOL specialDebugCase = _FALSE;
    static ET9BOOL debugThis1, debugThis2, debugThis3;

    ET9SYMB debugText[DEFAULT_WORD_SIZE + 1];
    static BYTE4 debugIndex1 = 0xFFFFFFFF;

    ET9SYMB debugText2[DEFAULT_WORD_SIZE + 1];
    static BYTE4 debugIndex2 = 0xFFFFFFFF;

    ET9SYMB debugText3[DEFAULT_WORD_SIZE + 1];
    static BYTE4 debugIndex3 = 0xFFFFFFFF;

    static SWSuffixTrace st[DEFAULT_WORD_SIZE];

    static ET9BOOL anyVersion = _TRUE;
    static ET9BOOL anyTapCount = _TRUE;
    static ET9BOOL exactCandidateIdx = _FALSE;
    static ET9BOOL rangeCandidateIdx = _FALSE;
    static ET9BOOL anyCandidateIdx = _TRUE;
#endif


#if SHOW_KEYPAIR_LIST
    static STRACHAR   checkChar1 = 'a';
    static STRACHAR   checkChar2 = 's';
    static STRACHAR   checkChar3 = 's';
    static STRACHAR   checkChar4 = 'h';
    static SBYTE2     checkCharTestVal = 4;
    SBYTE2 _SWCSearchDB_testKeys(BYTE1 key1, BYTE1 key2)
    {
        SBYTE2 retVal = 0;
        if ((key1 == pThis->m_backend->m_pDbm->charToKey1B(checkChar1)) && (key2 == pThis->m_backend->m_pDbm->charToKey1B(checkChar2)))
            return(4);
        if ((key1 == pThis->m_backend->m_pDbm->charToKey1B(checkChar3)) && (key2 == pThis->m_backend->m_pDbm->charToKey1B(checkChar4)))
            return(3);
        if ((key1 == pThis->m_backend->m_pDbm->charToKey1B(checkChar1)) && (key2 == pThis->m_backend->m_pDbm->charToKey1B(checkChar4)))
            return(2);
        if ((key1 == pThis->m_backend->m_pDbm->charToKey1B(checkChar3)) && (key2 == pThis->m_backend->m_pDbm->charToKey1B(checkChar2)))
            return(1);
        return(0);
    }
#endif

/*//////////////////////////////////////////////////////////////////// */
/* CSearchDB Construction/Destruction */
/*//////////////////////////////////////////////////////////////////// */

/* Complete initialization when a language has been fully loaded */
/* (because the CPU speed test used to rely on DBM calls). */
void ET9FARCALL _SWCSearchDB_Initialize(_SWCSearchDB *pThis)
{
    SBYTE2 i;

    /* Set Recency weighting factors.  Give a bigger score afvantage to less-frequent words when they have been flagged as recently used. */
    float freqInterval = (float)0.03;
    float freqBumpIncrement = (float)0.0025;
    float freqBump = (float)0.02;
    float weight = (float)1.0 - freqBump;

    pThis->Z1OperationSetting = 500;
#define FORCE_FREQ_FACTOR_INIT      1

    pThis->CurrentAlgorithm = ALG_ORIG_NEW2;               /* Index of current Search algorithm - init to MGD version */

#if FORCE_FREQ_FACTOR_INIT
    /* #define FORCE_FREQ_FACTOR_INIT for regression testing to enable repeated runs with the same start state */
    pThis->FreqRangeRatioInt = FREQ_RANGE_RATIO_INT_INIT;
#else
    /* If FreqRangeRatioInt value not yet saved in registry, then initialize it now */
    pThis->FreqRangeRatioInt = (BYTE2)pSettingsFile->ReadItem(SWSettingsFile::SETTING_FreqRangeRatio);
#endif
    pThis->FreqRangeRatio = (float)pThis->FreqRangeRatioInt / (float)FREQ_RANGE_RATIO_INT_DENOM;

    for (i = (FREQ_CLASS_COUNT - 1); i >= 0; i--)
    {
        pThis->RecencyWeight[i] = weight;
        weight -= freqInterval;
        freqInterval += freqBump;
        freqBump += freqBumpIncrement;
    }

    freqInterval = (float)0.02;
    freqBumpIncrement = (float)0.002;
    freqBump = (float)0.015;
    weight = (float)1.0 - freqBump;
    for (i = (FREQ_CLASS_COUNT - 1); i >= 0; i--)
    {
        pThis->RecencyWeightReduced[i] = weight;
        weight -= freqInterval;
        freqInterval += freqBump;
        freqBump += freqBumpIncrement;
    }

    freqInterval = (float)0.04;
    freqBumpIncrement = (float)0.002;
    freqBump = (float)0.025;
    weight = (float)1.0 - freqBump;
    for (i = (FREQ_CLASS_COUNT - 1); i >= 0; i--)
    {
        pThis->RecencyWeightIncreased[i] = weight;
        weight -= freqInterval;
        freqInterval += freqBump;
        freqBump += freqBumpIncrement;
    }

    freqInterval = (float)0.015;
    freqBumpIncrement = (float)0.00125;
    freqBump = (float)0.00125;
    weight = (float)1.0 - freqBump;
    for (i = (FREQ_CLASS_COUNT_MGD - 1); i >= 0; i--)
    {
        pThis->RecencyWeightMGD[i] = weight;
        weight -= freqInterval;
        freqInterval += freqBump;
        freqBump += freqBumpIncrement;
    }

    freqInterval = (float)0.01;
    freqBumpIncrement = (float)0.00075;
    freqBump = (float)0.0005;
    weight = (float)1.0 - freqBump;
    for (i = (FREQ_CLASS_COUNT_MGD - 1); i >= 0; i--)
    {
        pThis->RecencyWeightReducedMGD[i] = weight;
        weight -= freqInterval;
        freqInterval += freqBump;
        freqBump += freqBumpIncrement;
    }

    freqInterval = (float)0.02;
    freqBumpIncrement = (float)0.00135;
    freqBump = (float)0.00135;
    weight = (float)1.0 - freqBump;
    for (i = (FREQ_CLASS_COUNT_MGD - 1); i >= 0; i--)
    {
        pThis->RecencyWeightIncreasedMGD[i] = weight;
        weight -= freqInterval;
        freqInterval += freqBump;
        freqBump += freqBumpIncrement;
    }

#if DEBUG_SHOW_WCW_TRACE
        Log(SWLogger_DEBUG, TEXT(" \n ==> RecencyWeight[] =             %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->RecencyWeight[0], pThis->RecencyWeight[1], pThis->RecencyWeight[2], pThis->RecencyWeight[3], pThis->RecencyWeight[4], pThis->RecencyWeight[5], pThis->RecencyWeight[6], pThis->RecencyWeight[7]);
        Log(SWLogger_DEBUG, TEXT(" \n ==> RecencyWeightReduced[] =      %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->RecencyWeightReduced[0], pThis->RecencyWeightReduced[1], pThis->RecencyWeightReduced[2], pThis->RecencyWeightReduced[3], pThis->RecencyWeightReduced[4], pThis->RecencyWeightReduced[5], pThis->RecencyWeightReduced[6], pThis->RecencyWeightReduced[7]);
        Log(SWLogger_DEBUG, TEXT(" \n ==> RecencyWeightIncreased[] =    %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n\n"), pThis->RecencyWeightIncreased[0], pThis->RecencyWeightIncreased[1], pThis->RecencyWeightIncreased[2], pThis->RecencyWeightIncreased[3], pThis->RecencyWeightIncreased[4], pThis->RecencyWeightIncreased[5], pThis->RecencyWeightIncreased[6], pThis->RecencyWeightIncreased[7]);
        Log(SWLogger_DEBUG, TEXT(" \n ==> RecencyWeightMGD[] =          %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->RecencyWeightMGD[0], pThis->RecencyWeightMGD[1], pThis->RecencyWeightMGD[2], pThis->RecencyWeightMGD[3], pThis->RecencyWeightMGD[4], pThis->RecencyWeightMGD[5], pThis->RecencyWeightMGD[6], pThis->RecencyWeightMGD[7]);
        Log(SWLogger_DEBUG, TEXT(   "                                   %.3f %.3f %.3f %.3f %.3f %.3f %.3f \n"), pThis->RecencyWeightMGD[8], pThis->RecencyWeightMGD[9], pThis->RecencyWeightMGD[10], pThis->RecencyWeightMGD[11], pThis->RecencyWeightMGD[12], pThis->RecencyWeightMGD[13], pThis->RecencyWeightMGD[14]);
        Log(SWLogger_DEBUG, TEXT(" \n ==> RecencyWeightReducedMGD[] =   %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->RecencyWeightReducedMGD[0], pThis->RecencyWeightReducedMGD[1], pThis->RecencyWeightReducedMGD[2], pThis->RecencyWeightReducedMGD[3], pThis->RecencyWeightReducedMGD[4], pThis->RecencyWeightReducedMGD[5], pThis->RecencyWeightReducedMGD[6], pThis->RecencyWeightReducedMGD[7]);
        Log(SWLogger_DEBUG, TEXT(   "                                   %.3f %.3f %.3f %.3f %.3f %.3f %.3f \n"), pThis->RecencyWeightReducedMGD[8], pThis->RecencyWeightReducedMGD[9], pThis->RecencyWeightReducedMGD[10], pThis->RecencyWeightReducedMGD[11], pThis->RecencyWeightReducedMGD[12], pThis->RecencyWeightReducedMGD[13], pThis->RecencyWeightReducedMGD[14]);
        Log(SWLogger_DEBUG, TEXT(" \n ==> RecencyWeightIncreasedMGD[] = %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->RecencyWeightIncreasedMGD[0], pThis->RecencyWeightIncreasedMGD[1], pThis->RecencyWeightIncreasedMGD[2], pThis->RecencyWeightIncreasedMGD[3], pThis->RecencyWeightIncreasedMGD[4], pThis->RecencyWeightIncreasedMGD[5], pThis->RecencyWeightIncreasedMGD[6], pThis->RecencyWeightIncreasedMGD[7]);
        Log(SWLogger_DEBUG, TEXT(   "                                   %.3f %.3f %.3f %.3f %.3f %.3f %.3f \n"), pThis->RecencyWeightIncreasedMGD[8], pThis->RecencyWeightIncreasedMGD[9], pThis->RecencyWeightIncreasedMGD[10], pThis->RecencyWeightIncreasedMGD[11], pThis->RecencyWeightIncreasedMGD[12], pThis->RecencyWeightIncreasedMGD[13], pThis->RecencyWeightIncreasedMGD[14]);

        Log(SWLogger_DEBUG, TEXT(   "SearchDB class storage is %d bytes.\n"), sizeof(_SWCSearchDB));
#endif

    /* Give highest frequency class half the benefit even if not yet used to help avoid recognition failures */
    /*   for high-frequency short words at start-up. */
    pThis->Class7MinRecencyWeight = ((float)1.0 + pThis->RecencyWeight[MAX_FREQ_CLASS]) / (float)2.0;
    pThis->Class7MinRecencyWeightReduced = ((float)1.0 + pThis->RecencyWeightReduced[MAX_FREQ_CLASS]) / (float)2.0;
    pThis->Class7MinRecencyWeightIncreased = ((float)1.0 + pThis->RecencyWeightIncreased[MAX_FREQ_CLASS]) / (float)2.0;

    /* Make sure that FreqWeight[]/FreqWeightMGD[] are set to appropriate "generic" values (implied "average" pen speed and IP count) */
    _SWCSearchDB_SetFreqWeights(pThis, pThis->FreqRangeRatio, ALG_ORIG_NEW2, _FALSE);
    _SWCSearchDB_SetFreqWeights(pThis, pThis->FreqRangeRatio, ALG_MGD, _TRUE);

    /* TODO: Ensure that frequency weights are set prior to calling SetZ1OperationSetting()! */
    pThis->Z1OperationLevelPrevious = -1;                     /* Init to invalid values */
    _SWCSearchDB_SetZ1OperationSetting(pThis, pThis->Z1OperationSetting);         /* Trigger calls to SetZ1Operation() for each iteration level */

    {
        BYTE1 i;
        for (i = 0; i < SWDbm_rowCnt(pThis->m_backend->m_pDbm); i++) {
            pThis->rowCenter[i] = (SWDbm_getRowBoundsScaled(pThis->m_backend->m_pDbm, i + 1) + SWDbm_getRowBoundsScaled(pThis->m_backend->m_pDbm, i)) / 2;
        }
    }

#if SCOREWORD_API

    pThis->m_wSearchLevel = SearchLevelMaxVal;

    /* Initialize thresholds for value used in current pass */
    pThis->Z1OperationLevelCurrent = pThis->Z1IterationLevels[pThis->m_wSearchLevel];

    if (!pThis->IPThresholdLevelsSet)
        _SWCSearchDB_SetZ1Operation(pThis);

#endif /* SCOREWORD_API */

    pThis->m_initialized = _TRUE;

    /* SavedCodeSegments/SearchDB.cpp/46 */
}

/*============================================================================= */
/* Function:    _SWCSearchDB_CSearchDB() */
/* Parameters:  None */
/* Description: Construct the Word List filler object. */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

void ET9FARCALL _SWCSearchDB_Construct(_SWCSearchDB *pThis)
{
    pThis->m_initialized = _FALSE;

    pThis->wFixedDataCount = 0;

/*==============================================// */
/*      Initialization & Static Definition      // */
/*==============================================// */

    pThis->RenderIPsFlag = SHOW_IPS_INIT;
    pThis->Z1OperationSetting = DEFAULT_Z1_OPERATION_LEVEL;           /* Current value of Z1OperationLevel from registry */


    pThis->TrackZ1Stats = _FALSE;

    pThis->CurrentAlgorithm = ALG_ORIG_NEW2;               /* Index of current Search algorithm */

    /* Values to set for ALG_ORIG_NEW2 vs. ALG_MGD: */
    __SDB_INIT_2(algRecalcsThresholds, _TRUE, _FALSE);
    __SDB_INIT_2(algNewNoPenaltyScore, _TRUE, _TRUE);
    __SDB_INIT_2(algNewCombinedScore, _TRUE, _TRUE);

    __SDB_INIT_2(algNoReprocIPTable, _FALSE, _FALSE);
    __SDB_INIT_2(algReduceRecencyWeight, _FALSE, _TRUE);
    __SDB_INIT_2(algIncreaseRecencyWeight, _FALSE, _FALSE);
/* Note: algReduceFrequencyWeight (if _TRUE) has precedence over algIncreaseFrequencyWeight */
    __SDB_INIT_2(algReduceFrequencyWeight, _FALSE, _FALSE);
    __SDB_INIT_2(algIncreaseFrequencyWeight, _FALSE, _FALSE);
    __SDB_INIT_2(algIncreaseClass0FrequencyWeight, _FALSE, _FALSE);
/* Following values used in morphing ALG_MGD_PREV, with new features enabled only in ALG_MGD */
    __SDB_INIT_2(algAddUndershootToMaxLen, _FALSE, _TRUE);
    __SDB_INIT_2(algConvertAngleCloseToAngle, _FALSE, _TRUE);
    __SDB_INIT_2(algDeleteAngleCloseToAngle, _TRUE, _FALSE);

    __SDB_INIT_2(algConvertAngleCloseToPenDown, _FALSE, _FALSE);
    __SDB_INIT_2(algReduceMGDScoreThresholds, _FALSE, _TRUE);

    pThis->IPThresholdFactor = IP_THRESHOLD_FACTOR_LEVEL_INIT;
    pThis->SegmentThresholdFactor = SEGMENT_THRESHOLD_FACTOR_LEVEL_INIT;

/* Add silent "e": t, m, s, l, */

/* Map terminal: y -> e, k -> c, */

/* Other pairs: ca/ke, ci/sy, do/du, ef/ep(h), ek/ec, ek/eq, er/ea(rring), ex/es, */

/*   maximum expected processing times */

    /* This is set in KeyboardChanged() */
    pThis->isMGDataBase = _FALSE;

    pThis->m_pZ1FixedData = NULL;
    pThis->thisWord = NULL;                 /* Current word being analyzed */
    pThis->pathWidth = pThis->pathHeight = pThis->pathCenter = pThis->pathCenterFromRow = 0;
    pThis->m_SearchShiftPos[0] = 0;
    pThis->m_SearchExitXPos[0] = 0;
    pThis->m_SearchEntryXPos[0] = 0;
    pThis->m_SearchEntryPosIndex[0] = 0;
    pThis->m_SearchShiftLocCount = 0;
    pThis->m_SearchShiftAll = _FALSE;
    pThis->m_wRequiredIPTableCount = 0;
    pThis->actualPath = pThis->minPath = pThis->maxPath = 0;
    pThis->m_wSearchLevel = 0;
    pThis->overshootPathLen = 0;
    pThis->rawDistKey[0] = pThis->rawScoreKey[0] = 0;
    pThis->weightSumKey[0] = 0;
    pThis->skipPenaltyKey[0] = 0;
    pThis->skippedIPsCount[0] = 0;
    pThis->ipIndexKey[0] = 0;
    pThis->slopeFactorKey[0] = 0;
    /* SavedCodeSegments/277 - PERFORM_FUTURE_MATCH_CHECK code */
    pThis->ipData = pThis->seg1Data = pThis->ipData2 = pThis->seg2Data = pThis->ipData3 = pThis->seg3Data = NULL;
    pThis->reScoreSuffix = _FALSE;
    pThis->calculatingKeyPairs = _FALSE;
    pThis->rawDist = pThis->rawScore = 0;
    pThis->rawSlopeScore = 0;
    pThis->penaltyRawScore = 0;
    pThis->weightSum = 0;
    pThis->slopeFactorTotal = 0;
    pThis->penaltySlopeFactor = 0;
    pThis->skipPenaltyWord = 0;
    pThis->skippedIPsWord = 0;
    pThis->ipIndex = pThis->keyIndex = pThis->keyIndexM1 = pThis->key2Index = pThis->key3Index = pThis->keySeqLength = pThis->keysRemaining = pThis->ipsRemaining = pThis->lastOmittedKey = 0;
    pThis->transposeCount = pThis->vowelTransposeCount = pThis->omissionCount = pThis->omitCount = pThis->substituteCount = pThis->multipleIPCount = pThis->multipleIPsTotal = 0;
    pThis->wordMinX = pThis->wordMaxX = pThis->wordMinY = pThis->wordMaxY = pThis->wordWidth = pThis->wordHeight = 0;
    pThis->pathSize = 0;
    pThis->maxCandidateIPPenalty = pThis->maxCandidateIPPenaltyBase = pThis->maxCandidateSpellPenalty = pThis->maxSuffixCandidatePenalty = 0;
    pThis->doubleKeyCount = pThis->repeatedKeyCount = pThis->nextDoubleKeyIndex = 0;
    pThis->doubleKeyIndices[0] = 0;
    pThis->key1 = pThis->key2 = pThis->key3 = pThis->key4 = pThis->lastKey = 0;
    pThis->matchKey = pThis->dualMatch = 0;
    pThis->matchKeyPos = pThis->altMatchKeyPos = pThis->lastMatchKeyPos = pThis->altLastMatchKeyPos = pThis->dualMatchPos = _SWPoint_Construct_SSB1SB1(0, 0);
    pThis->matchKeyPosIndex = pThis->altMatchKeyPosIndex = pThis->lastMatchKeyPosIndex = pThis->altLastMatchKeyPosIndex = pThis->dualMatchPosIndex = pThis->lastSkipPosIndex = 0;
    pThis->finalMatchPosIndex = pThis->finalRequiredIPPosIndex = 0;
    pThis->altMatchKeyType = pThis->altLastMatchKeyType = 0;
    pThis->altMatchKeyRawScore = pThis->altLastMatchKeyRawScore = pThis->altMatchKeyRawDist = pThis->altLastMatchKeyRawDist = 0;
    pThis->altMatchKeyWeightSum = pThis->altLastMatchKeyWeightSum = (float)0.0;
    pThis->matchKeyLoc = pThis->altMatchKeyLoc = pThis->altMatchKeyLoc2 = pThis->lastMatchKeyLoc = pThis->altLastMatchKeyLoc = pThis->dualMatchLoc = _SWPoint_Construct_SSB1SB1(0, 0);
    pThis->matchKeyLoc3 = pThis->altMatchKeyLoc3 = _SWPoint_Construct_SSB1SB1(0, 0);
    pThis->matchKeyLocIndex = pThis->matchKeyLocExitIndex = pThis->altMatchKeyLocIndex = pThis->altMatchKeyLocExitIndex = pThis->lastMatchKeyLocIndex = pThis->altLastMatchKeyLocIndex = pThis->dualMatchLocIndex = 0;
    pThis->altMatchKeyLocIndex2 = pThis->matchKeyLocIndex3 = pThis->altMatchKeyLocIndex3 = 0;
    pThis->matchSlopeDifFactor = pThis->dualSlopeDifFactor = 0;
    pThis->key1IP1 = pThis->key1Seg1 = pThis->key1IP2 = pThis->key1Seg2 = pThis->key1IP3 = pThis->key1Seg3 = 0;
    pThis->key2IP1 = pThis->key2Seg1 = pThis->key2IP2 = pThis->key2Seg2 = pThis->key2IP3 = pThis->key2Seg3 = 0;
    pThis->key3IP1 = pThis->key3Seg1 = pThis->key3IP2 = pThis->key3Seg2 = pThis->key3IP3 = pThis->key3Seg3 = 0;
    pThis->key4IP1 = pThis->key4IP2 = 0;
    pThis->keyMultipleIPs = pThis->keyMultipleIPsDistance = pThis->keyMultipleIPsWDistance = 0;
    pThis->key1Seg1PosIndex = pThis->key1Seg2PosIndex = pThis->key1Seg3PosIndex = 0;
    pThis->key2Seg1PosIndex = pThis->key2Seg2PosIndex = pThis->key2Seg3PosIndex = 0;
    pThis->key3Seg1PosIndex = pThis->key3Seg2PosIndex = pThis->key3Seg3PosIndex = 0;
    pThis->isCandidate = pThis->requiredIP = pThis->key1IsDoubleKey = pThis->key2IsDoubleKey = pThis->key3IsDoubleKey = pThis->lastKeyMatchesPenUp = pThis->finalKeyScoreAdjusted = _FALSE;
    pThis->IP1isPenUp = pThis->IP2isPenUp = pThis->IP3isPenUp = pThis->IP1canBePenUp = pThis->IP1isPathDivision = pThis->IP2isPathDivision = pThis->IP3isPathDivision = _FALSE;
    pThis->IP1isMultiple = pThis->IP2isMultiple = pThis->IP3isMultiple = _FALSE;
    pThis->IP1isArtificial = pThis->IP2isArtificial = pThis->IP3isArtificial = _FALSE;
    pThis->advanceIP = pThis->advanceKey = pThis->finalKey = pThis->exitLoop = pThis->finalScoringPass = _FALSE;
    pThis->isSwappedKey = pThis->wasSwappedKey = _FALSE;
    pThis->mergedIP = 0;
    pThis->penaltyAvDistance = 0;
    pThis->penaltyAvScore = 0;
    pThis->avSlopeFactor = 0;
    pThis->bFirstKeyboardInit = _TRUE;

    /* initialize IP Table array position pointers */
    pThis->goodEnoughScore = pThis->goodEnoughScoreCurrent = GOOD_ENOUGH_SCORE_INIT;

    pThis->IPThresholdFactor = IP_THRESHOLD_FACTOR_LEVEL_INIT;
    pThis->SegmentThresholdFactor = SEGMENT_THRESHOLD_FACTOR_LEVEL_INIT;

    _SWCSearchDB_ClearSearchIPTable(pThis);

} /* _SWCSearchDB_CSearchDB() */

ET9BOOL ET9FARCALL _SWCSearchDB_KeyboardChanged(_SWCSearchDB *pThis)
{
    pThis->isMGDataBase = _FALSE;

    if (pThis->bFirstKeyboardInit)
    {
        pThis->bFirstKeyboardInit = _FALSE;

        if (!pThis->m_initialized)
            _SWCSearchDB_Initialize(pThis);
    }
    return _TRUE;
}

#if DEBUG_LOG_MATCH_TRACE

static int ET9LOCALCALL _SWCSearchDB_IsDebugText(_SWCSearchDB *pThis, _SWWord *checkWord)
{
    size_t checkLength;
    if (specialDebugCase)
    {
        debugThis = debugThis1 = _TRUE;
        return(1);
    }
    checkLength = checkWord->textLen;
    debugThis = debugThis1 = debugThis2 = debugThis3 = _FALSE;
    if (checkLength > 0)
    {
        if ((checkLength == wcslen((wchar_t *)debugText)) && (!_ET9symbnicmp(checkWord->externalText, debugText, ET9MAXUDBWORDSIZE, _ET9AWSP_DATA->dwSwypeWordLocale) || (checkWord->wordIndex == debugIndex1)))
        {
            debugThis = debugThis1 = _TRUE;
            return(1);
        }
        else if ((checkLength == wcslen((wchar_t *)debugText2)) && (!_ET9symbnicmp(checkWord->externalText, debugText2, ET9MAXUDBWORDSIZE, _ET9AWSP_DATA->dwSwypeWordLocale) || (checkWord->wordIndex == debugIndex2)))
        {
            debugThis = debugThis2 = _TRUE;
            return(2);
        }
        else if ((checkLength == wcslen((wchar_t *)debugText3)) && (!_ET9symbnicmp(checkWord->externalText, debugText3, ET9MAXUDBWORDSIZE, _ET9AWSP_DATA->dwSwypeWordLocale) || (checkWord->wordIndex == debugIndex3)))
        {
            debugThis = debugThis3 = _TRUE;
            return(3);
        }
    }
    return(0);
}

#endif


/*============================================================================= */
/* Function:    _SWCSearchDB_SetFreqWeights() */
/* Parameters:  None */
/* Description: Set current values for FreqWeight[] or FreqWeightMGD[]. */
/*============================================================================= */

void ET9FARCALL _SWCSearchDB_SetFreqWeights(_SWCSearchDB *pThis, float RunTimeFreqRange, ALGORITHM_TYPE searchAlgorithm, ET9BOOL setForMGD)
{
    SBYTE2 i;
    float freqIntervalBase, freqInterval, freqBumpIncrement, freqBump, weight;
    /*float RunTimeFreqRange = (FreqRangeRatio * penSpeedFactor * ipCountFactor); */
    if (RunTimeFreqRange > FREQ_RANGE_RATIO_MAX)
        RunTimeFreqRange = FREQ_RANGE_RATIO_MAX;
    else if (RunTimeFreqRange < FREQ_RANGE_RATIO_MIN)
        RunTimeFreqRange = FREQ_RANGE_RATIO_MIN;
    if (!setForMGD)
    {
        if (pThis->algReduceFrequencyWeight[searchAlgorithm])
        {
            /*freqIntervalBase = (float)0.33 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT - 1); */
            /*freqBumpIncrement = RunTimeFreqRange / (float)255.0; */
            /*freqIntervalBase = (float)0.50 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT - 1); */
            /*freqBumpIncrement = RunTimeFreqRange / (float)63.0; */
            freqIntervalBase = (float)0.61 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT - 1);
            freqBumpIncrement = RunTimeFreqRange / (float)41.0;
            /*freqIntervalBase = (float)0.1 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT - 1); */
            /*freqBumpIncrement = RunTimeFreqRange / (float)255.0; */
        }
        else if (pThis->algIncreaseFrequencyWeight[searchAlgorithm])
        {
            freqIntervalBase = (float)0.70 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT - 1);
            freqBumpIncrement = RunTimeFreqRange / (float)32.0;
        }
        else        /* original algorithm... */
        {
            freqIntervalBase = (float)0.66666667 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT - 1);
            freqBumpIncrement = RunTimeFreqRange / (float)36.0;
        }
        freqInterval = (float)0.0;
        freqBump = (float)0.0;
        pThis->FreqWeight[FREQ_CLASS_COUNT - 1] = (float)1.0;
        weight = (float)2.0;                  /* Frequency factor is always 1.0 for class 7, 2.0 for class 6 */
        /*weight = (float)1.2;                  // Frequency factor is always 1.0 for class 7, 2.0 for class 6 */
        for (i = (FREQ_CLASS_COUNT - 2); i >= 0; i--)
        {
            weight += freqInterval;
            pThis->FreqWeight[i] = weight;
            /* Add extra weight to lower classes, particularly class 0, so that if a word is demoted to this level, it will not win out over */
            /* a similar word that has been promoted up to class 6. */
            if (i == 3)
                freqBump += 2 * freqBumpIncrement;
            else if (i == 2)
                freqBump += 3 * freqBumpIncrement;
            else if (i == 1)
                freqBump += 6 * freqBumpIncrement;
            else
                freqBump += freqBumpIncrement;
            freqInterval = freqIntervalBase + freqBump;
        }
        if (pThis->algIncreaseClass0FrequencyWeight[searchAlgorithm])
        {
            pThis->FreqWeight[0] += freqInterval / 2;
        }
    }
    else
    {
        if (pThis->algReduceFrequencyWeight[searchAlgorithm])
        {
            /*freqIntervalBase = (float)0.33 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT_MGD - 1); */
            /*freqBumpIncrement = RunTimeFreqRange / (float)255.0; */
            /*freqIntervalBase = (float)0.50 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT_MGD - 1); */
            /*freqBumpIncrement = RunTimeFreqRange / (float)63.0; */
            freqIntervalBase = (float)0.61 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT_MGD - 1);
            freqBumpIncrement = RunTimeFreqRange / (float)41.0;
        }
        else if (pThis->algIncreaseFrequencyWeight[searchAlgorithm])
        {
            freqIntervalBase = (float)0.75 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT_MGD - 1);
            freqBumpIncrement = RunTimeFreqRange / (float)60.0;
        }
        else        /* original algorithm... */
        {
            freqIntervalBase = (float)0.66666667 * RunTimeFreqRange / (float)(FREQ_CLASS_COUNT_MGD - 1);
            freqBumpIncrement = RunTimeFreqRange / (float)45.0;
        }
        freqInterval = freqIntervalBase;
        freqBump = freqBumpIncrement;
        weight = (float)1.0;                  /* Frequency factor is always 1.0 for class 7 (class 14 for MGD...) */
        for (i = (FREQ_CLASS_COUNT_MGD - 1); i >= 0; i--)
        {
            pThis->FreqWeightMGD[i] = weight;
            weight += freqInterval;
            freqInterval = freqIntervalBase + freqBump;
            freqBump += freqBumpIncrement;
        }
        if (pThis->algIncreaseClass0FrequencyWeight[searchAlgorithm])
        {
            pThis->FreqWeight[0] += (2 * freqInterval) / 3;
            pThis->FreqWeight[1] += freqInterval / 3;
        }
    }
}

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1FixedDataSize() */
/* Parameters:  None */
/* Description: Return the number of SWFixedData points saved */
/*============================================================================= */

SBYTE2 ET9FARCALL _SWCSearchDB_GetZ1FixedDataSize(_SWCSearchDB *pThis)
{
    return pThis->wFixedDataCount;
} /* _SWCSearchDB_GetZ1FixedDataSize() */

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1FixedData() */
/* Parameters:  fixedIndex - Index of desired Fixed mouse data element */
/* Description: Return the Fixed data object of the desired element. */
/*              Return the last element if index is too large so that pointer */
/*              is always legal. */
/*=============================================================================             //lint !e744 */

SWFixedData* ET9FARCALL _SWCSearchDB_GetZ1FixedData(_SWCSearchDB *pThis, SBYTE2 fixedIndex)
{
    if ((fixedIndex < 0) || (fixedIndex >= pThis->wFixedDataCount)) {
        return NULL;
    }

    return &pThis->m_pZ1FixedData[fixedIndex];
} /* _SWCSearchDB_GetZ1FixedData() */

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1FixedPoint() */
/* Parameters:  fixedIndex - Index of desired Fixed mouse data element */
/* Description: Return the point position of the desired element. */
/*============================================================================= */

_SWPoint ET9FARCALL _SWCSearchDB_GetZ1FixedPoint(_SWCSearchDB *pThis, SBYTE2 fixedIndex)
{
    /* get a pointer to the fixed mouse data */
    SWFixedData *fixedData = _SWCSearchDB_GetZ1FixedData(pThis, fixedIndex);
    if (fixedData != NULL)
        return fixedData->m_Point;
    else
        return _SWPoint_Construct_SSB2SB2((SBYTE2)0, (SBYTE2)0);
} /* _SWCSearchDB_GetZ1FixedPoint() */

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1FixedD2Sum() */
/* Parameters:  fixedIndex - Index of desired Fixed mouse data element */
/* Description: Return the D2Sum field value of the desired element. */
/*============================================================================= */

SBYTE4 ET9FARCALL _SWCSearchDB_GetZ1FixedD2Sum(_SWCSearchDB *pThis, SBYTE2 fixedIndex)
{
    /* get a pointer to the fixed mouse data */
    SWFixedData *fixedData = _SWCSearchDB_GetZ1FixedData(pThis, fixedIndex);
    if (fixedData != NULL)
        return fixedData->D2Sum;
    else
        return (SBYTE4)0;
} /* _SWCSearchDB_GetZ1FixedD2Sum() */

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1PathLength() */
/* Parameters:  fixedIndex - Index of desired Fixed mouse data elements */
/* Description: Return the length of the path between the desired elements. */
/*============================================================================= */

BYTE2 ET9FARCALL _SWCSearchDB_GetZ1PathLength(_SWCSearchDB *pThis, SBYTE2 fixedIndex1, SBYTE2 fixedIndex2)
{
    /* Calculate precise actual distance between the two fixed points */
    BYTE4   precisePathLen = _SWCSearchDB_GetZ1PathLengthPrecise(pThis, fixedIndex1, fixedIndex2);
    BYTE2   pathLen = (BYTE2)((precisePathLen + PRECISION_ADJ_VAL/2) >> PRECISION_ADJ_EXP);       /* Round to nearest distance value */
    return(pathLen);
} /* _SWCSearchDB_GetZ1PathLength() */

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1PathLength8() */
/* Parameters:  fixedIndex - Index of desired Fixed mouse data elements */
/* Description: Return the length8 of the path between the desired elements. */
/*============================================================================= */

BYTE2 ET9FARCALL _SWCSearchDB_GetZ1PathLength8(_SWCSearchDB *pThis, SBYTE2 fixedIndex1, SBYTE2 fixedIndex2)
{
    /* Calculate precise actual distance between the two fixed points */
    BYTE4   precisePathLen = _SWCSearchDB_GetZ1PathLengthPrecise(pThis, fixedIndex1, fixedIndex2);
    BYTE2   pathLen8 = (BYTE2)((precisePathLen + (1 << (PRECISION_ADJ_EXP - 4))) >> (PRECISION_ADJ_EXP - 3));       /* Round to nearest distance8 value */
    return(pathLen8);
} /* _SWCSearchDB_GetZ1PathLength8() */

/*============================================================================= */
/* Function:    _SWCSearchDB_GetZ1PathLengthPrecise() */
/* Parameters:  fixedIndex - Index of desired Fixed mouse data elements */
/* Description: Return the precise actual length of the path between the desired elements. */
/*============================================================================= */

BYTE4 ET9FARCALL _SWCSearchDB_GetZ1PathLengthPrecise(_SWCSearchDB *pThis, SBYTE2 fixedIndex1, SBYTE2 fixedIndex2)
{
    if (pThis->m_pZ1FixedData == NULL)
        return(0);
    {
        BYTE4   precisePathLen;
        SBYTE2  fixedLimit = pThis->wFixedDataCount;

        if (fixedIndex1 >= fixedIndex2) /* Check that params are in proper order */
        {
            if (fixedIndex1 == fixedIndex2)
                return (0);
            {
                SBYTE2 temp = fixedIndex1;
                fixedIndex1 = fixedIndex2;
                fixedIndex2 = temp;
            }
        }
        if (fixedIndex1 >= fixedLimit)
            fixedIndex1 = fixedLimit - 1;
        if (fixedIndex2 >= fixedLimit)
            fixedIndex2 = fixedLimit - 1;
        if (fixedIndex1 < 0)
            fixedIndex1 = 0;
        if (fixedIndex2 < 0)
            fixedIndex2 = 0;
        /* Calculate precise actual distance between the two fixed points */
        precisePathLen = pThis->m_pZ1FixedData[fixedIndex2].m_PrecisePathLen -
                            pThis->m_pZ1FixedData[fixedIndex1].m_PrecisePathLen;
        return(precisePathLen);
    }
} /* _SWCSearchDB_GetZ1PathLengthPrecise() */


/*============================================================================= */
/* Function:    AdjustWordFrequency */
/* Parameters:  ET9AWLingInfo * const pLingInfo - Pointer to alphabetic information structure. */
/*              const ET9U8 bWordIndex - Word index of base 0. */
/*              ET9BOOL corrected - true if word was selected (or cancelled) from an Editing list */
/* Description: Release the Word List data mutex so another process can use it. */
/*============================================================================= */
ET9BOOL ET9FARCALL _SWCSearchDB_AdjustWordFrequency(_SWCSearchDB *pThis, ET9AWLingInfo * const pLingInfo,
                                      const ET9U8 bWordIndex,
                                      ET9BOOL corrected)
{
    ET9_UNUSED(pThis);
    ET9_UNUSED(pLingInfo);
    ET9_UNUSED(bWordIndex);
    ET9_UNUSED(corrected);
#if TBD_ADJUST_FREQUENCY_WEIGHTS
    ET9BOOL    CanPromote, CanDemote;
    ET9BOOL    alreadyPromoted = _FALSE;

    /* If selected word is not the default word (word was "eclipsed", check whether one or more frequency classes should be adjusted */
    /* Frequency adjustment rules: */
    /*  1. Class 7 words are "locked" in class 7 */
    /*  2. All other words are locked OUT of class 7 (i.e. class 6 or lower) */
    /*  3. Promote words toward class average of class 5 (FREQ_CLASS_GOAL) - i.e. balance promotions and demotions */
    /*  4. Don't "crowd" words in class 7 - i.e. if default word is class 7, don't promote eclipsed word higher than (MAX_FREQ_CLASS - MAX_FREQ_MARGIN) */

    for (SBYTE2 listIdx = 0; listIdx < bWordIndex; listIdx++)
    {
        /* Identify higher-placed word for frequency processing.  Clear recent use bit for any word that scored higher than intended word. */
        if (corrected)
        {
            listWord = &pThis->m_backend->m_pDbm->editWordList[listIdx];
            if (listWord)
                pThis->m_backend->m_pDbm->resetRecentUse(listWord->wordIndex, listWord->isUser);
        }
        else
        {
            listWord = wordList.GetWord(listIdx);
            if ((listWord != NULL) && (listWord->kind != _SWWordBase::WT_TAPPED))
                pThis->m_backend->m_pDbm->resetRecentUse(listWord->wordIndex, listWord->isUser);
        }
        if (listWord == NULL)
            return(_FALSE);
        /* If eclipsed word was actually "as close or closer" to the input path but still had a lower FinalScore, then increase its frequency.  If eclipsed word */
        /*   cannot be promoted and default word was > class 0, then demote the default word. */
        /* Only adjust frequencies if penalties for selected word are no higher than for default word, or if the penalties can reasonably be attributed */
        /*   to the absence of a double-letter gesture when such gestures are not strictly required, and */
        /*   if the two words do not actually map to the same stem... */
        if ((dbWord->betterScore || (dbWord->kind == _SWWordBase::WT_PREDICTION)) && (!pThis->isMGDataBase || (dbWord->rootIdx != listWord->rootIdx)))
        {
            CanPromote = (!alreadyPromoted && (dbWord->freqStem < (MAX_FREQ_CLASS - 1)));    /* Don't promote words into class 7 */
            CanDemote = ((listWord->freqStem < MAX_FREQ_CLASS) && (listWord->freqStem > 0));    /* Don't decrease frequency of words in class 7 */
            /* Decrease frequency range factor if lower frequency word eclipsed by higher frequency word */
            /*   despite having better score prior to frequency weighting */
            SBYTE2 adjustRange = 0;
            if (listWord->freqStem > dbWord->freqStem)
            {
                /* Decrease FreqRangeRatio factor */
                /* Lower by 10% of remaining interval to minimum value */
                pThis->FreqRangeRatio -= (float)0.1 * (pThis->FreqRangeRatio - FREQ_RANGE_RATIO_MIN);
                if (pThis->FreqRangeRatio < FREQ_RANGE_RATIO_MIN)
                    pThis->FreqRangeRatio = FREQ_RANGE_RATIO_MIN;
                adjustRange = -1;
            }
            /* Raise frequency range factor if higher frequency word eclipsed by lower frequency word */
            /*   (lower frequency word MUST have had a better score) */
            else if (listWord->freqStem < dbWord->freqStem)
            {
                /* Raise by 10% of remaining interval to maximum value */
                pThis->FreqRangeRatio += (float)0.1 * (FREQ_RANGE_RATIO_MAX - pThis->FreqRangeRatio);
                if (pThis->FreqRangeRatio > FREQ_RANGE_RATIO_MAX)
                    pThis->FreqRangeRatio = FREQ_RANGE_RATIO_MAX;
                adjustRange = 1;
            }
            if (adjustRange)
            {
                pThis->FreqRangeRatioInt = (BYTE2)(long)(pThis->FreqRangeRatio * FREQ_RANGE_RATIO_INT_DENOM);
                SWSettingsFile* pSettingsFile = SWSettingsFile::GetInstance();
                SWSettingsFile::SettingsFileEditor settingsFileEditor(*pSettingsFile);
                settingsFileEditor.WriteSetting(SWSettingsFile::SETTING_FreqRangeRatio, pThis->FreqRangeRatioInt);

#if SHOW_FREQ_RATIO_CHANGES
                if (adjustRange > 0)
                {
                    Log(SWLogger::STATS_DEBUG, L" FreqRangeRatio RAISED to = %f", pThis->FreqRangeRatio);
#if OUTPUT_STATS1_FILE
                    LogSTATS(SWLogger::STATS_DEBUG,L" FreqRangeRatio RAISED to = %f", pThis->FreqRangeRatio);
#endif
                }
                else
                {
                    Log(SWLogger::STATS_DEBUG, L" FreqRangeRatio LOWERED to = %f", pThis->FreqRangeRatio);
#if OUTPUT_STATS1_FILE
                    LogSTATS(SWLogger::STATS_DEBUG,L" FreqRangeRatio LOWERED to = %f", pThis->FreqRangeRatio);
#endif
                }
#endif
            }
        }
        else
        {
            CanPromote = _FALSE;
            CanDemote = _FALSE;
        }
        /* Increase frequency of eclipsed word if allowed && currently lower frequency, or if eclipsing word already at class 0 */
        if (CanPromote && ((listWord->freqStem >= dbWord->freqStem) || !CanDemote))
        {
            pThis->m_backend->m_pDbm->changeFreqForWord(dbWord, (dbWord->freqStem + 1));             /* change frequency of eclipsed word to new value */
            alreadyPromoted = _TRUE;
#if SHOW_FREQ_RATIO_CHANGES
            Log(SWLogger_INFO, L" Word: %s PROMOTED to class %d \n", dbWord->externalText.GetString(), (dbWord->freqStem + 1));
#endif
        }
        else if (CanDemote)                                                 /* Don't decrease frequency of words in class 7 */
        {
            pThis->m_backend->m_pDbm->changeFreqForWord(listWord, (listWord->freqStem - 1));   /* change frequency of default word to new value */
#if SHOW_FREQ_RATIO_CHANGES
            Log(SWLogger_INFO, L" Word: %s DEMOTED to class %d \n", listWord->externalText.GetString(), (listWord->freqStem - 1));
#endif
        }
        /* If word was eclipsed by a user word in the default position, then generate CSH to inform user that the word can be deleted. */
        if ((listWord->kind == _SWWordBase::WT_USER) && (listIdx == 0) && !tappedWord)
        {
            const STRCHAR* tmp = TEXT("<^^>");
            DebugAssert(dbWord->externalText.GetLength());
            DebugAssert(listWord->externalText.GetLength());
            Str customText = dbWord->externalText + tmp + listWord->externalText + tmp + listWord->externalText;
            pOS->VerbalUserFeedback(pOS->VUF_CSH_IMMEDIATE, (BYTE4)'W', &customText);
        }
    }
    /* Set recent use bit for accepted word */
    if (dbWord->kind != _SWWordBase::WT_TAPPED)
        pThis->m_backend->m_pDbm->setRecentUse(dbWord->wordIndex, dbWord->isUser);

    DebugAssert(pThis->m_backend->m_pDbm->popLanguage());
#endif /* TBD_ADJUST_FREQUENCY_WEIGHTS */
    return _TRUE;
} /* _SWCSearchDB_ScoreWordFromKeyRepeats(pThis) */

/*============================================================================= */
/* Function:    _SWCSearchDB_PathExitsKeyboard() */
/* Parameters:  BYTE2 fixedIndex1, fixedIndex2 - Indices of fixed points */
/* Returns:     SBYTE2 - X-coordinate of where path exits and re-enters keyboard between the */
/*              two fixed points (always non-zero), or 0 if no exit-entry between */
/*              the points. */
/* Description: Determine whether the path exits the keyboard along the specified */
/*              path segment. */
/*============================================================================= */

SBYTE2 ET9FARCALL _SWCSearchDB_PathExitsKeyboard(_SWCSearchDB *pThis, SBYTE2 fixedIndex1, SBYTE2 fixedIndex2, SBYTE2 *exitXPos, SBYTE2 *entryPosIndex)
{
    SBYTE2 i;
    for (i = 0; i < pThis->m_SearchShiftLocCount; i++)
    {
        if (_SWCSearchDB_PointsInSequenceOrIdentical(pThis, fixedIndex1, pThis->m_SearchShiftPos[i]) &&
            _SWCSearchDB_PointsInSequenceOrIdentical(pThis, pThis->m_SearchShiftPos[i], fixedIndex2))
        {
            *exitXPos = (pThis->forward) ? pThis->m_SearchExitXPos[i] : pThis->m_SearchEntryPosIndex[i];
            *entryPosIndex = (pThis->forward) ? pThis->m_SearchEntryPosIndex[i] : pThis->m_SearchShiftPos[i];
            return((pThis->forward) ? pThis->m_SearchEntryXPos[i] : pThis->m_SearchExitXPos[i]);
        }
    }
    *exitXPos = 0;
    return 0;
} /* _SWCSearchDB_PathExitsKeyboard */

float ET9FARCALL _SWCSearchDB_calcVectorDif(_SWCSearchDB *pThis, BYTE1 key_2, BYTE1 key_3, SBYTE2 matchKeyPosIndex_2, SBYTE2 matchKeyPosIndex_3, _SWVector keyVector, _SWVector pathVector, BYTE2 *keyVectorLength)
{
    _SWVector   keyVector2, pathVector2;
    SBYTE2      keyVectorChange, pathVectorChange;
    _SWPoint    matchKeyPos_2, matchKeyPos_3;

    SWDbm_getKeyPairDataScaled(pThis->m_backend->m_pDbm, key_2, key_3, &keyVector2);          /* Get key vector from database */
    *keyVectorLength = (BYTE2)keyVector2.length;
    matchKeyPos_2 = _SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex_2);
    matchKeyPos_3 = _SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex_3);
    pathVector2 = _SWVector_Construct_SPP(&matchKeyPos_2, &matchKeyPos_3);
    keyVectorChange = _SWVector_signedSlopeDifference(&keyVector, &keyVector2);
    /* If vectors differ by more than 90 degrees, the approximation to radians deteriorates. */
    /* Swap locations in second vector to keep slope difference less than 90 degrees */
    /*   (use already-computed equivalent (non-inverted) pathVector2 if key slope difference less than 90 degrees) */
    if (absGeo(keyVectorChange) > RIGHT_ANGLE_VECTOR_SLOPE_DIF)
    {
        SWDbm_getKeyPairDataScaled(pThis->m_backend->m_pDbm, key_3, key_2, &keyVector2);      /* Get inverted key vector from database */
        keyVectorChange = _SWVector_signedSlopeDifference(&keyVector, &keyVector2);  /* Re-calculate slope difference */
        pathVector2 = _SWVector_Construct_SPP(&matchKeyPos_3, &matchKeyPos_2);       /* Get corresponding inverted 2nd path vector */
    }
    pathVectorChange = _SWVector_signedSlopeDifference(&pathVector, &pathVector2);

    return((float)absGeo(keyVectorChange - pathVectorChange));
}

#define USE_VECTOR_DIF_TO_PENALIZE_SCORE   0
#define USE_VECTOR_DIF_TO_IMPROVE_SCORE    0
#define USE_VECTOR_DIF_TO_ADJUST_SCORE     (USE_VECTOR_DIF_TO_PENALIZE_SCORE || USE_VECTOR_DIF_TO_IMPROVE_SCORE)

ET9BOOL ET9FARCALL _SWCSearchDB_calcSlopeDif(_SWCSearchDB *pThis, BYTE1 key_1, BYTE1 key_2, BYTE1 key_3, ET9BOOL swappedKey, ET9BOOL suffixCheck, _SWPoint matchKeyPos_1, _SWPoint matchKeyPos_2,
                             SBYTE2 matchKeyPosIndex_1, SBYTE2 matchKeyPosIndex_2, float *slopeDifFactor,
                             float *lengthFactor, SBYTE2 matchKeyPosIndex_3, SBYTE2 altKeyPosIndex1, SBYTE2 altKeyPosIndex2, SBYTE2 altKeyPosIndex22, ET9BOOL adjustForPathLength)
{
    _SWVector   keyVector, pathVector, altPathVector;
    _SWPoint    altKeyPos1, altKeyPos2;
    float       slopeDif, slopeThreshold, altSlopeDif, slopeFactor;
    ET9BOOL     adjacentKeys = _FALSE;
    ET9BOOL     slopeOK;
    float       lengthEffect = MIN_LENGTH_EFFECT;
    ET9BOOL     limitMaxSlopeDifFactor = _FALSE;
    BYTE2       pathLen, straightLen;
    SBYTE2      exitX, entryPosIndex;
    SBYTE2      entryX;
    ET9_UNUSED(matchKeyPosIndex_3);
    ET9_UNUSED(suffixCheck);

    *slopeDifFactor = DEFAULT_SLOPE_FACTOR;      /* Init to default values */
    *lengthFactor = DEFAULT_LENGTH_FACTOR;
    SWDbm_getKeyPairDataScaled(pThis->m_backend->m_pDbm, key_1, key_2, &keyVector);           /* Get key vector from database */
    pathVector = _SWVector_Construct_SPP(&matchKeyPos_1, &matchKeyPos_2);
    slopeDif = (float)_SWVector_slopeDifference(&pathVector, &keyVector);
    /* If neither key has been swapped, use minimum possible slopeDif if alternate match locations provided */
    if (!swappedKey && pThis->thisKeyCheckAlternateMatches)
    {
        if (altKeyPosIndex1)
        {
            altKeyPos1 = _SWCSearchDB_GetZ1FixedPoint(pThis, altKeyPosIndex1);
            altPathVector = _SWVector_Construct_SPP(&altKeyPos1, &matchKeyPos_2);
            altSlopeDif = (float)_SWVector_slopeDifference(&altPathVector, &keyVector);
            if (altSlopeDif < slopeDif)
            {
                slopeDif = altSlopeDif;
                pathVector = altPathVector;
            }
        }
        if (altKeyPosIndex2)
        {
            altKeyPos2 = _SWCSearchDB_GetZ1FixedPoint(pThis, altKeyPosIndex2);
            altPathVector = _SWVector_Construct_SPP(&matchKeyPos_1, &altKeyPos2);
            altSlopeDif = (float)_SWVector_slopeDifference(&altPathVector, &keyVector);
            if (altSlopeDif < slopeDif)
            {
                slopeDif = altSlopeDif;
                pathVector = altPathVector;
            }
            if (altKeyPosIndex1)
            {
                altPathVector = _SWVector_Construct_SPP(&altKeyPos1, &altKeyPos2);
                altSlopeDif = (float)_SWVector_slopeDifference(&altPathVector, &keyVector);
                if (altSlopeDif < slopeDif)
                {
                    slopeDif = altSlopeDif;
                    pathVector = altPathVector;
                }
            }
        }
        if (altKeyPosIndex22)
        {
            altKeyPos2 = _SWCSearchDB_GetZ1FixedPoint(pThis, altKeyPosIndex22);
            altPathVector = _SWVector_Construct_SPP(&matchKeyPos_1, &altKeyPos2);
            altSlopeDif = (float)_SWVector_slopeDifference(&altPathVector, &keyVector);
            if (altSlopeDif < slopeDif)
            {
                slopeDif = altSlopeDif;
                pathVector = altPathVector;
            }
            if (altKeyPosIndex1)
            {
                altPathVector = _SWVector_Construct_SPP(&altKeyPos1, &altKeyPos2);
                altSlopeDif = (float)_SWVector_slopeDifference(&altPathVector, &keyVector);
                if (altSlopeDif < slopeDif)
                {
                    slopeDif = altSlopeDif;
                    pathVector = altPathVector;
                }
            }
        }
    }
    /* Set threshold level for difference in slope depending on how close the two keys are. */
    /* Threshold must be greater when keys are closer. */
    if (keyVector.length <= ADJACENT_KEY_DISTANCE_THRESHOLD)
    {
        adjacentKeys = _TRUE;
        slopeThreshold = ADJACENT_KEY_SLOPE_THRESHOLD;
        slopeFactor = ADJACENT_SLOPE_FACTOR_INTERVAL;
        limitMaxSlopeDifFactor = pThis->calculatingKeyPairs;        /* Limit for initial and final key pair calculations */
    }
    else if (keyVector.length >= DISTANT_KEY_DISTANCE_THRESHOLD)
    {
        slopeThreshold = DISTANT_KEY_SLOPE_THRESHOLD;
        slopeFactor = DISTANT_SLOPE_FACTOR_INTERVAL;
        lengthEffect = MAX_LENGTH_EFFECT;
    }
    else
    {
        float segmentLen = (float)(keyVector.length - ADJACENT_KEY_DISTANCE_THRESHOLD);
        lengthEffect += (segmentLen / (float)(DISTANT_KEY_DISTANCE_THRESHOLD - ADJACENT_KEY_DISTANCE_THRESHOLD)) * (MAX_LENGTH_EFFECT - MIN_LENGTH_EFFECT);
        slopeThreshold = ADJACENT_KEY_SLOPE_THRESHOLD - (lengthEffect * (ADJACENT_KEY_SLOPE_THRESHOLD - DISTANT_KEY_SLOPE_THRESHOLD));
        slopeFactor = ADJACENT_SLOPE_FACTOR_INTERVAL - (lengthEffect * (ADJACENT_SLOPE_FACTOR_INTERVAL - DISTANT_SLOPE_FACTOR_INTERVAL));
    }
    if (swappedKey && (!_SWCSearchDB_isVowelKey(pThis, key_2, _TRUE) || (!_SWCSearchDB_isVowelKey(pThis, key_1, _TRUE) && !_SWCSearchDB_isVowelKey(pThis, key_3, _TRUE))))
    {
        slopeThreshold *= SWAPPED_KEY_SLOPE_THRESHOLD_FACTOR;
        slopeFactor *= SWAPPED_KEY_SLOPE_FACTOR_FACTOR;
    }
    slopeOK = (ET9BOOL)(slopeDif <= slopeThreshold);
#if USE_VECTOR_DIF_TO_PENALIZE_SCORE
    BYTE2   keyVector2Length;
    if (slopeOK && matchKeyPosIndex_3 && (key_3 != SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)) && (matchKeyPosIndex_3 != matchKeyPosIndex_2))
    {
        float vectorDif;
        if (suffixCheck)        /* If we are checking matches in a suffix, key_3 is the key preceding key_1 */
            vectorDif = calcVectorDif(key_3, key_1, matchKeyPosIndex_3, matchKeyPosIndex_1, keyVector, pathVector, keyVector2Length);
        else
            vectorDif = calcVectorDif(key_2, key_3, matchKeyPosIndex_2, matchKeyPosIndex_3, keyVector, pathVector, keyVector2Length);

#if USE_VECTOR_DIF_TO_PENALIZE_SCORE
        if (vectorDif > slopeDif)
        {
            float   vectorLengthEffect;
            /* Reset threshold level for difference in slope depending on the closer of the two pairs of keys. */
            /* Threshold must be greater when keys are closer. */
            if (keyVector2Length < keyVector.length)
            {
                if (keyVector2Length <= pThis->m_backend->sScreenGeometry.keyWidth)
                {
                    slopeThreshold = ADJACENT_KEY_SLOPE_THRESHOLD;
                    slopeFactor = ADJACENT_SLOPE_FACTOR_INTERVAL;
                    vectorLengthEffect = 0.0;
                }
                else if (keyVector2Length >= (6 * pThis->m_backend->sScreenGeometry.keyWidth))
                {
                    slopeThreshold = DISTANT_KEY_SLOPE_THRESHOLD;
                    slopeFactor = DISTANT_SLOPE_FACTOR_INTERVAL;
                    vectorLengthEffect = 1.0;
                }
                else
                {
                    BYTE2 segmentLen = (BYTE2)(keyVector2Length - pThis->m_backend->sScreenGeometry.keyWidth);
                    vectorLengthEffect = (float)segmentLen / (float)(5 * pThis->m_backend->sScreenGeometry.keyWidth);
                    slopeThreshold = ADJACENT_KEY_SLOPE_THRESHOLD - (vectorLengthEffect * (ADJACENT_KEY_SLOPE_THRESHOLD - DISTANT_KEY_SLOPE_THRESHOLD));
                    slopeFactor = ADJACENT_SLOPE_FACTOR_INTERVAL - (vectorLengthEffect * (ADJACENT_SLOPE_FACTOR_INTERVAL - DISTANT_SLOPE_FACTOR_INTERVAL));
                }
            }
            else
                vectorLengthEffect = lengthEffect;
            if (vectorDif > slopeThreshold)     /* re-check slopeThreshold */
            {
                /* Since the initial slopeDif test passed, try alternate key_3 match location(s) if available */
                /* Note that the "key_3" parameter to this function is actually _SWCSearchDB_key2 whenever matchKeyPosIndex_3 is non-zero, except */
                /* when suffixCheck is true, or when called to test a possible multiple IPs match (?) */
                if ((key_3 == key2) && !suffixCheck)
                {
                    /* If we first tried an IP match, check either current and/or next segment match */
                    float vectorDif1, vectorDif2;
                    if ((matchKeyPosIndex_3 == pThis->ipData->m_IPPosIndex) && (pThis->key2Seg1 || pThis->key2Seg2))
                    {
                        if (pThis->key2Seg1PosIndex)
                            vectorDif1 = calcVectorDif(key_2, key_3, matchKeyPosIndex_2, pThis->key2Seg1PosIndex, keyVector, pathVector, keyVector2Length);
                        else
                            vectorDif1 = (float)10000.0;            /* Arbitrary large value */
                        if (pThis->key2Seg2PosIndex)
                            vectorDif2 = calcVectorDif(key_2, key_3, matchKeyPosIndex_2, pThis->key2Seg2PosIndex, keyVector, pathVector, keyVector2Length);
                        else
                            vectorDif2 = (float)10000.0;            /* Arbitrary large value */
                        vectorDif = sw_min(vectorDif1, vectorDif2);
                    }       /* Try IP match id segment match failed */
                    else if ((matchKeyPosIndex_3 == pThis->key2Seg1PosIndex) || (matchKeyPosIndex_3 == pThis->key2Seg2PosIndex))
                    {
                        vectorDif1 = calcVectorDif(key_2, key_3, matchKeyPosIndex_2, pThis->ipData->m_IPPosIndex, keyVector, pathVector, keyVector2Length);
                        if ((matchKeyPosIndex_3 == pThis->key2Seg1PosIndex) && pThis->key2Seg2PosIndex)
                            vectorDif2 = calcVectorDif(key_2, key_3, matchKeyPosIndex_2, pThis->key2Seg2PosIndex, keyVector, pathVector, keyVector2Length);
                        else if ((matchKeyPosIndex_3 == pThis->key2Seg2PosIndex) && pThis->key2Seg1PosIndex)
                            vectorDif2 = calcVectorDif(key_2, key_3, matchKeyPosIndex_2, pThis->key2Seg1PosIndex, keyVector, pathVector, keyVector2Length);
                        else
                            vectorDif2 = (float)10000.0;            /* Arbitrary large value */
                        vectorDif = sw_min(vectorDif1, vectorDif2);
                    }
                }
                if (vectorDif > slopeThreshold)     /* re-check slopeThreshold */
                {
#if DEBUG_SHOW_MATCH_TRACE
                    if (debugThis)
                    {
                        if (pThis->forward && (pThis->thisWord != NULL))
                        {
                            Log(SWLogger_DEBUG,TEXT(" vectorDif fails slopeThreshold test in KeysMatchPoints() for key[%d] in %s \r\n"), key_2, SWLangUtil::ConvertInternalToExternal(pThis->thisWord->text.GetString()).GetString());
                        }
                        else if (!pThis->forward && (thisSuffix != NULL))
                        {
                            Log(SWLogger_DEBUG,TEXT(" vectorDif fails slopeThreshold test in KeysMatchPoints() for key[%d] in suffix %s \r\n"), key_2, SWLangUtil::ConvertInternalToExternal(thisSuffix->text.GetString()).GetString());
                        }
                    }
#endif
                    slopeOK = _FALSE;
                }
            }
            slopeDif = vectorDif;
            if (vectorLengthEffect > lengthEffect)
            {
                lengthEffect = vectorLengthEffect;
            }
        }
#endif
#if USE_VECTOR_DIF_TO_IMPROVE_SCORE
        if (vectorDif < slopeDif)
        {
            slopeDif = vectorDif;
            /*if (vectorLengthEffect < lengthEffect) */
            /*{ */
            /*    lengthEffect = vectorLengthEffect; */
            /*} */
        }
#endif
    }
#endif
    *slopeDifFactor = ((slopeDif / slopeFactor) + SLOPE_FACTOR_BASE) / SLOPE_FACTOR_BASE;
    /* For initial key pair evaluation, limit dynamic range of slopeDifFactor */
    if (limitMaxSlopeDifFactor && (*slopeDifFactor > MAX_ADJACENT_SLOPE_DIF_FACTOR) && slopeOK)
        *slopeDifFactor = MAX_ADJACENT_SLOPE_DIF_FACTOR + ((float)0.2 * (*slopeDifFactor - MAX_ADJACENT_SLOPE_DIF_FACTOR));

    /* SavedCodeSegments/287 - Previous lengthFactor adjustment */
    /* If shift gesture detected, "entry point" should be relatively close */
    /*   to key_2, and "exit point" should be relatively close to key_1 (note that points */
    /*   returned by PathExitsKeyboard() are relative to value of forward */
    entryX = _SWCSearchDB_PathExitsKeyboard(pThis, matchKeyPosIndex_1, matchKeyPosIndex_2, &exitX, &entryPosIndex);
    if (entryX)
    {
        _SWPoint tempPt;
        SBYTE2 totalHorizontalDisplacement;
        pathLen = _SWCSearchDB_GetZ1PathLength8(pThis, entryPosIndex, matchKeyPosIndex_2);
        _SWPoint_Construct_SB2SB2(&tempPt, entryX, (SBYTE2)0);
        straightLen = _SWPoint_distance8(&matchKeyPos_2, &tempPt);
        totalHorizontalDisplacement = (SBYTE2)(absGeo(matchKeyPos_1.x - exitX) + absGeo(matchKeyPos_2.x - entryX));
        if (totalHorizontalDisplacement > SHIFT_GESTURE_ENTRY_THRESHOLD)
        {
            float adjustFactor = sw_min((float)1.67, ((float)totalHorizontalDisplacement /(float)SHIFT_GESTURE_ENTRY_THRESHOLD));
            *slopeDifFactor *= adjustFactor;
        }
    }
    /* Set slopeDifFactor to 0.0 (to flag replacement with average value) if one or more IPs skipped between matching points */
    else
    {
        pathLen = _SWCSearchDB_GetZ1PathLength8(pThis, matchKeyPosIndex_1, matchKeyPosIndex_2);
        straightLen = _SWPoint_distance8(&matchKeyPos_1, &matchKeyPos_2);
        if (!pThis->calculatingKeyPairs && pThis->lastSkipPosIndex &&
            _SWCSearchDB_PointsInSequence(pThis, matchKeyPosIndex_1, pThis->lastSkipPosIndex) &&
            _SWCSearchDB_PointsInSequence(pThis, pThis->lastSkipPosIndex, matchKeyPosIndex_2))
        {
            if ((pThis->lastOmittedKey > 0) && (pThis->keyIndex == (pThis->lastOmittedKey + 1)))
            {
                pThis->substituteCount++;
                pThis->lastOmittedKey = -1;        /* Make sure omitted key counted as substitution only once */
            }
            *slopeDifFactor = (float)0.0;
        }
    }
    if (adjustForPathLength && (pathLen > straightLen))
    {
        float lengthRatio = (float)pathLen / (float)straightLen;
        /* For keys that are very close to each other (i.e. less than 1 1/2 key-widths apart), allow for a disproportionately longer penalty-free */
        /* path-length to allow "hopping" between adjacent keys without imposing a large scoring penalty for an (apparently) indirect path */
        if (adjacentKeys && (lengthRatio > DEFAULT_ADJACENT_HOPPING_LENGTH_FACTOR))
        {
            if (lengthRatio < MAX_ADJACENT_HOPPING_LENGTH_FACTOR)
                lengthRatio = DEFAULT_ADJACENT_HOPPING_LENGTH_FACTOR;
            else
                lengthRatio -= ADJACENT_HOPPING_LENGTH_FACTOR_ADJUSTMENT;
        }

        /* Reduce lengthRatio (by at least 50% or by lengthEffect) if path is within top row of keyboard with adjacent u, i and 0. */
        /* Check ends of path and mid-point.  This allows "tap-dancing" on keys in the top alphabetic */
        /* row (e.g. to get "pout" rather than "put") without over-penalizing for necessarily curved paths. */
        if (pThis->vowelKeysLowerBound > 0)
        {
            ET9BOOL pos1Qualifies = (ET9BOOL)((matchKeyPos_1.y <= pThis->vowelKeysLowerBound) &&
                                  (matchKeyPos_1.x >= pThis->vowelKeysLeftBound) &&
                                  (matchKeyPos_1.x <= pThis->vowelKeysRightBound) &&
                                  (_SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex_1 + 2).y <= (matchKeyPos_1.y - HOPPING_GESTURE_VERTICAL_MARGIN)) &&
                                  (_SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex_1 - 2).y <= (matchKeyPos_1.y - HOPPING_GESTURE_VERTICAL_MARGIN)));
            ET9BOOL eitherPosQualifies = (ET9BOOL)(pos1Qualifies ||
                                  ((matchKeyPos_2.y <= pThis->vowelKeysLowerBound) &&
                                   (matchKeyPos_2.x >= pThis->vowelKeysLeftBound) &&
                                   (matchKeyPos_2.x <= pThis->vowelKeysRightBound) &&
                                   (_SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex_2 + 2).y <= (matchKeyPos_2.y - HOPPING_GESTURE_VERTICAL_MARGIN)) &&
                                   (_SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex_2 - 2).y <= (matchKeyPos_2.y - HOPPING_GESTURE_VERTICAL_MARGIN))));
            if (eitherPosQualifies)
            {
                lengthRatio = (float)1.0 + (sw_min(lengthEffect, (float)0.50) * (lengthRatio - (float)1.0));
            }
        }
        /* Set lengthFactor by (approximately) raising lengthRatio to the "1.25" power. */
        {
            float lengthRatioAdjust = (float)1.0 + ((float)0.25 * (lengthRatio - (float)1.0));
            if (lengthRatioAdjust > ((float)1.0 + lengthEffect))
                lengthRatioAdjust = (float)1.0 + lengthEffect;
            *lengthFactor = lengthRatio * lengthRatioAdjust;
        }

        /* Increase slope factor for final key when there are only two (required) IPs (this addresses the "its" vs. "is" case, */
        /*   where the slope factor for "is" happens to be quite small (due to matching locations) despite significant */
        /*   curvature in the path. */
        if (!pThis->calculatingKeyPairs && !adjacentKeys && (pThis->seg1Data != NULL))
        {
            if (pThis->forward && (pThis->m_wRequiredIPTableCount == 2) && (pThis->keysRemaining == 1) && (pThis->keySeqLength == 2) && /* (*slopeDifFactor < (float)1.1) && */
                (((pathLen - straightLen) >= SIGNIFICANT_CURVATURE_DIFFERENCE) || (pThis->seg1Data->m_fLengthRatio >= SIGNIFICANT_CURVATURE_RATIO)))
            {
                *slopeDifFactor *= LENGTH_RATIO_ADJUST_FOR_TWO_IPS * pThis->seg1Data->m_fLengthRatio;
            }
        }
        if (*lengthFactor > MAX_CURVED_LENGTH_FACTOR)
            *lengthFactor = MAX_CURVED_LENGTH_FACTOR;
        *slopeDifFactor = *lengthFactor * *slopeDifFactor;
    }
    return(slopeOK);
}   /* CSearchDB::calcSlopeDif() */

/*============================================================================= */
/* Function:    _SWCSearchDB_KeysMatchPoints() */
/* Parameters:  BYTE1 key_1 - First key index of ordered pair of keys to be matched */
/*              with the points on the input path */
/*              BYTE1 key_2 - Second key index of ordered pair of keys */
/*              ET9BOOL isSegmentMatch- Set true if key_2 is matched to a segment point (rather */
/*              than an IP) */
/*              ET9BOOL swappedKey- Set true if key_1 or key_2 has been swapped from its actual order */
/*              in the word being scored */
/*              SWPoint matchKeyLoc1 - Location on input path near where first key of */
/*              ordered pair of keys was matched, where D2Sum reaches a local maximum */
/*              SWPoint matchKeyLoc2 - Location on input path near where key_2 was matched, */
/*              where D2Sum reaches a local maximum */
/*              SBYTE2 matchKeyLocIndex1, matchKeyLocIndex2 - Fixed index of path locations */
/*              where local D2Sum maxima are detected */
/*              SWPoint  matchKeyPos1, matchKeyPos2 - Actual path locations */
/*              where key_1 and key_2 are matched (closest path locations or IP locations) */
/*              SBYTE2 matchKeyPosIndex1, matchKeyPosIndex2 - Fixed index of actual path locations */
/*              where key_1 and key_2 are matched (closest path locations or IP locations) */
/*              SBYTE2 matchKeyPosIndex2Alt - If non-zero, this is an attempted segment match, */
/*              and this value is the fixed index of the following hypothesized match location */
/*              SBYTE2 altKeyPosIndex1 - If non-zero, this is an alternate matching location for key_1 */
/*              SBYTE2 altKeyPosIndex2 - If non-zero, this is an alternate matching location for key_2 */
/* Description: Compare the slope of the vector from key_1 to key_2 with the slope */
/*              of the vector connecting the points on the path that are associated */
/*              with each key.  Return true if vectors have similar slopes, and if */
/*              points occur in proper order along path. */
/*============================================================================= */

ET9BOOL ET9FARCALL _SWCSearchDB_KeysMatchPoints(_SWCSearchDB *pThis, BYTE1 key_1, BYTE1 key_2, BYTE1 key_3, ET9BOOL isSegmentMatch, ET9BOOL swappedKey, ET9BOOL suffixCheck,
                                _SWPoint matchKeyLoc_1, _SWPoint matchKeyLoc_2, SBYTE2 matchKeyLoc_Index1, SBYTE2 matchKeyLoc_Index2,
                                _SWPoint matchKeyPos_1, _SWPoint matchKeyPos_2, SBYTE2 matchKeyPos_Index1, SBYTE2 matchKeyPos_Index2,
                                float *slopeDifFactor, SBYTE2 matchKeyPosIndex2Alt, SBYTE2 altKeyPosIndex1, SBYTE2 altKeyPosIndex2,
                                SBYTE2 altKeyPosIndex22, ET9BOOL adjustForPathLength)
{
    float       lengthFactor;

#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis1)
        debugThis1 = _TRUE;
    if (debugThis2)
        debugThis2 = _TRUE;
    if (debugThis3)
        debugThis3 = _TRUE;
#endif
    *slopeDifFactor = DEFAULT_SLOPE_FACTOR;      /* Init to default value */
    pThis->oddPathPenalty = (float)0.0;
    /* Match is OK if only one actual key is being matched (e.g. for 1-letter suffix where (pThis->lastKey == SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))) */
    if ((key_1 == SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)) || (key_2 == SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        return _TRUE;
    }
    /* Return _FALSE if points in reverse order along path, or if they are matched to the same point on a segment */
    /* Disqualify match if both pairs are in reverse order */
    if (!_SWCSearchDB_PointsInSequenceOrIdentical(pThis, matchKeyPos_Index1, matchKeyPos_Index2) &&
        !_SWCSearchDB_PointsInSequenceOrIdentical(pThis, matchKeyLoc_Index1, matchKeyLoc_Index2))
        return _FALSE;
    /* If one pair is equal, then other must be in proper order */
    if ((matchKeyPos_Index1 == matchKeyPos_Index2) || (matchKeyLoc_Index1 == matchKeyLoc_Index2))
    {
        if (!_SWCSearchDB_PointsInSequenceOrIdentical(pThis, matchKeyPos_Index1, matchKeyPos_Index2) ||
            !_SWCSearchDB_PointsInSequenceOrIdentical(pThis, matchKeyLoc_Index1, matchKeyLoc_Index2) ||
             (isSegmentMatch && (matchKeyPos_Index1 == matchKeyPos_Index2) && (matchKeyLoc_Index1 == matchKeyLoc_Index2)))
            return _FALSE;
    }

    /* If not calculating final score, return after above basic consistency check */
    if (!pThis->finalScoringPass && !swappedKey)
        return _TRUE;
#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis1)
        debugThis1 = _TRUE;
    if (debugThis2)
        debugThis2 = _TRUE;
    if (debugThis3)
        debugThis3 = _TRUE;
#endif
    /* Return default values if keys matched to same point */
    if (_SWPoint_Equals(&matchKeyPos_1, &matchKeyPos_2) && (matchKeyPos_Index1 == matchKeyPos_Index2) && (matchKeyLoc_Index1 == matchKeyLoc_Index2))
        return _TRUE;
    if (_SWPoint_Equals(&matchKeyPos_1, &matchKeyPos_2))     /* Use alternate Loc if same points passed in */
    {
        if (matchKeyLoc_Index1 != matchKeyLoc_Index2)
        {
            matchKeyPos_1 = matchKeyLoc_1;
            matchKeyPos_2 = matchKeyLoc_2;
        }
        else
        {
            matchKeyPos_1 = _SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPos_Index1);
            matchKeyPos_2 = _SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPos_Index2);
        }
    }
    /* Calculate slopeDifFactor and confirm validity */
    if (!_SWCSearchDB_calcSlopeDif(pThis, key_1, key_2, key_3, swappedKey, suffixCheck, matchKeyPos_1, matchKeyPos_2, matchKeyLoc_Index1, matchKeyLoc_Index2,
                         slopeDifFactor, &lengthFactor, matchKeyPosIndex2Alt, altKeyPosIndex1, altKeyPosIndex2, altKeyPosIndex22, adjustForPathLength))
        return _FALSE;

    /* SavedCodeSegments/291 - Adjustments now moved inside calcSlopeDif() */
    if (adjustForPathLength)
    {
        /* SavedCodeSegments/292 - Adjustments now moved inside calcSlopeDif() */
        if (lengthFactor > MAX_NO_PENALTY_LENGTH_FACTOR)
        {
            if (lengthFactor > EXCESSIVE_LENGTH_FACTOR)
                pThis->oddPathPenalty = (MAX_NO_PENALTY_LENGTH_FACTOR * EXCESSIVE_CURVATURE_PENALTY) + ((lengthFactor - EXCESSIVE_LENGTH_FACTOR) * EXCESSIVE_CURVATURE_PENALTY2);
            else
                pThis->oddPathPenalty = lengthFactor * EXCESSIVE_CURVATURE_PENALTY;
            if (pThis->oddPathPenalty > MAX_CURVATURE_PENALTY)
                pThis->oddPathPenalty = MAX_CURVATURE_PENALTY;
        }
    }

    return _TRUE;
} /* _SWCSearchDB_KeysMatchPoints() */


BYTE2 ET9FARCALL _SWCSearchDB_GetIPWDistance(_SWCSearchDB *pThis, SWCIPTableRow *ipDat, BYTE1 key)
{
    BYTE2   retVal = 0;

    if ((ipDat != NULL) && (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        retVal = ipDat->m_IPWDistance8[key];
        if (retVal == W_DISTANCE8_MAX)
            retVal = 0;
    }
    return(retVal);
}

BYTE2 ET9FARCALL _SWCSearchDB_GetIPDistance8(_SWCSearchDB *pThis, SWCIPTableRow *ipDat, BYTE1 key)
{
    if ((ipDat != NULL) && (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        return(ipDat->m_IPAdjDistance8[key]);
    }
    return(DISTANCE8_MAX);
}

BYTE2 ET9FARCALL _SWCSearchDB_GetSegmentDistance8(_SWCSearchDB *pThis, SWCIPTableRow *segData, BYTE1 key)
{
    BYTE2   retVal = DISTANCE8_MAX;

    if ((segData != NULL) && (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        retVal = segData->m_SegmentDistance8[key];
        if (retVal < MIN_SEGMENT_DISTANCE8)
            retVal = (retVal + MIN_SEGMENT_DISTANCE8) / 2;      /* Force result >= MIN_SEGMENT_DISTANCE8? */
    }
    return(retVal);
}

/* Pass fixedLimit2 in as parameter (or 0 if called from ScoreSuffix()), and */
/*   return 0 if matching location for key is > fixedLimit2 */
BYTE2 ET9FARCALL _SWCSearchDB_GetSegmentWDistance(_SWCSearchDB *pThis, SWCIPTableRow *segData, BYTE1 key, SBYTE2 fixedLimit)
{
    BYTE2   retVal = 0;

    if ((segData != NULL) && (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        retVal = segData->m_SegmentWDistance8[key];
        if (retVal == W_DISTANCE8_MAX)
            retVal = 0;
        else if (fixedLimit && (segData->m_LinePos[key] > fixedLimit))
            retVal = 0;
    }
    return(retVal);
}

SBYTE2 ET9FARCALL _SWCSearchDB_GetSegmentMatchPos(_SWCSearchDB *pThis, SWCIPTableRow *segData, BYTE1 key, _SWPoint *matchPos, _SWPoint *matchLoc, SBYTE2 *matchLocIndex)
{
    SBYTE2 matchPosIndexRet = IPT_NO_MATCH;
    ET9BOOL   matchLocSet = _FALSE;
    ET9BOOL   matchPosSet = _FALSE;

    *matchLocIndex = 0;
    if ((segData != NULL) && (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        matchPosIndexRet = segData->m_LinePos[key];
        *matchLocIndex = segData->m_D2LocalMaxPos[key];
        if (*matchLocIndex != IPT_NO_MATCH)
        {
            *matchLoc = _SWCSearchDB_GetZ1FixedPoint(pThis, *matchLocIndex);
            matchLocSet = _TRUE;
        }
        if (matchPosIndexRet != IPT_NO_MATCH)
        {
            *matchPos = _SWCSearchDB_GetZ1FixedPoint(pThis, matchPosIndexRet);
            matchPosSet = _TRUE;
        }
    }
    if (!matchLocSet)
        _SWPoint_Construct_SB2SB2(matchLoc, (SBYTE2)0, (SBYTE2)0);
    if (!matchPosSet)
        _SWPoint_Construct_SB2SB2(matchLoc, (SBYTE2)0, (SBYTE2)0);
    return(matchPosIndexRet);
}

float ET9FARCALL _SWCSearchDB_GetSegmentMatchWeight(_SWCSearchDB *pThis, SWCIPTableRow *segData, BYTE1 key)
{
    float   segWeight = (float)0.01;        /* Avoid divide-by-zero errors */

    if ((segData != NULL) && (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
    {
        segWeight = segData->m_SegmentWeight[key];
    }
    return(segWeight);
}
#if DEBUG_SHOW_MATCH_TRACE || DEBUG_SHOW_WCW_TRACE
float ET9FARCALL _SWCSearchDB_GetSkippingPenalty(_SWCSearchDB *pThis, SWCIPTableRow *ipDat, SBYTE2 match_Key, ET9BOOL advance_IP, SBYTE2 *skippedIPs, float *IPskipPenalty, ET9BOOL isSuffix, float oddPathPenaltyVal)
{
    float penalty = _SWCSearchDB_GetSkippingPenalty1(pThis, ipDat, match_Key, advance_IP, skippedIPs, IPskipPenalty, isSuffix, oddPathPenaltyVal);
    if (penalty > 0.0)
    {
        if (debugThis1)
            pThis->bBreakHere = _TRUE;
        if (debugThis2)
            pThis->bBreakHere = _TRUE;
        if (debugThis3)
            pThis->bBreakHere = _TRUE;
    }
    return (penalty);
}

#if DEBUG_SHOW_WCW_TRACE
static ET9BOOL hasPathDivisionPenalty = _FALSE;
static ET9BOOL wasPathDivisionPenalty = _FALSE;
static int withPathDivisionPenalty = 0;
static int withoutPathDivisionPenalty = 0;
static int countPathDivisionPenalty = 0;
#endif

float ET9FARCALL _SWCSearchDB_GetSkippingPenalty1(_SWCSearchDB *pThis, SWCIPTableRow *ipDat, SBYTE2 match_Key, ET9BOOL advance_IP, SBYTE2 *skippedIPs, float *IPskipPenalty, ET9BOOL isSuffix, float oddPathPenaltyVal)
#else
float ET9FARCALL _SWCSearchDB_GetSkippingPenalty(_SWCSearchDB *pThis, SWCIPTableRow *ipDat, SBYTE2 match_Key, ET9BOOL advance_IP, SBYTE2 *skippedIPs, float *IPskipPenalty, ET9BOOL isSuffix, float oddPathPenaltyVal)
#endif
{
    float       penalty = 0.0;
    ET9BOOL     setlastSkipPosIndex = _FALSE;
    ET9BOOL     merged_IP;
    IPType      p_IPType;

    *IPskipPenalty = 0.0f;        /* Set to skipping penalty assessed for failure to match an IP */
    if (ipDat == NULL)
        return penalty;
    p_IPType = ipDat->m_IPType;
    if (((p_IPType == Exit) || (p_IPType == Multiple)) && (match_Key != THIS_SEGMENT_MATCH) && (match_Key != DOUBLE_KEYS_TO_SEGMENT_MATCH))
    {
        /*AlwaysAssert((match_Key == NO_PATTERN_MATCH)  || (match_Key >= OMIT_CURRENT_KEY)); */
        /*AlwaysAssert((match_Key == NO_PATTERN_MATCH)  || (p_IPType != PathDivision) || !pThis->advanceIP); */
        return penalty;
    }

    if ((match_Key >= IP_MATCH) && (match_Key <= SEGMENT_MATCH_ONLY))
    {
#if DEBUG_SHOW_WCW_TRACE
        if (oddPathPenaltyVal > (float)0.0)
        {
            if (debugThis)
                pThis->bBreakHere = _TRUE;
            if (wasPathDivisionPenalty)
                withPathDivisionPenalty++;
            else
                withoutPathDivisionPenalty++;
        }
#endif
        penalty += oddPathPenaltyVal;
    }

    /* If the path curves so much that a PathDivision IP is generated, there should have been at least one */
    /* preceding segment match.  If not, assess a small skipping penalty */
    if (p_IPType == PathDivision)
    {
        ET9BOOL setPenalty = (ET9BOOL)(pThis->advanceIP && (match_Key != THIS_SEGMENT_MATCH) && (match_Key != DOUBLE_KEYS_TO_SEGMENT_MATCH) &&
                           ((pThis->keyIndex < 2) || !pThis->hasSegmentMatch[pThis->keyIndex - 2] || (pThis->ipIndexKey[pThis->keyIndex - 2] < pThis->ipIndex - 1)));
        if (setPenalty)
        {
            penalty += PATH_DIVISION_WITHOUT_SEGMENT_MATCH;
#if DEBUG_SHOW_WCW_TRACE
            if ((oddPathPenaltyVal > (float)0.0) && !wasPathDivisionPenalty)
            {
                withPathDivisionPenalty++;
                withoutPathDivisionPenalty--;
            }
            wasPathDivisionPenalty = _TRUE;
            hasPathDivisionPenalty = _TRUE;
            countPathDivisionPenalty++;
#endif
        }
        return(penalty);
    }
#if DEBUG_SHOW_WCW_TRACE
    wasPathDivisionPenalty = _FALSE;
#endif
    merged_IP = (ipDat->m_MergeCount > 1);
    if ((match_Key == IP_MATCH) && (p_IPType != DoubleLetter))
    {
        if ((ipDat->m_DoubleIPIndex > 0) && (p_IPType != Multiple))         /* If this was an actual IP that was generated within a DoubleLetter gesture, then assess penalties */
        {
            if (ipDat->signChangesOK && (ipDat->circleScore >= MIN_ACCEPTABLE_CIRCLE_SCORE))
                penalty += (ipDat->circleScore * SINGLE_KEY_TO_DOUBLE_IP);
        }
        if (merged_IP)
            penalty += SINGLE_KEY_TO_MERGED_IP;
        return(penalty);
    }
    if (match_Key == DOUBLE_KEYS_TO_SINGLE_IP_MATCH)
    {
#if CAN_REQUIRE_DOUBLE_GESTURE
        if (pThis->doubleGestureRequired)
        {
            float ipCountAdjust = (float)4.0 / (float)(sw_min(pThis->m_wIPTableCount, 8));   /* Factor ranges from 2.0 to 0.5 for 2 to 8+ IPs */
            if (!merged_IP)
            {
                if (pThis->m_wIPTableCount == 2)
                    penalty += pThis->DoubleKeysToSingleIPOnly2IPsPenalty;
                else if (pThis->m_wIPTableCount == 3)
                    penalty += pThis->DoubleKeysToSingleIPOnly3IPsPenalty;
                return(ipCountAdjust * (penalty + DOUBLE_KEYS_TO_SINGLE_IP));
            }
            else
                return(ipCountAdjust * (penalty + pThis->DoubleKeysToMergedIPPenalty));
        }
        else
#endif
        {
            if (!merged_IP)
            {
                if (pThis->m_wIPTableCount == 2)
                    penalty += pThis->DoubleKeysToSingleIPOnly2IPsPenalty;
                else if (pThis->m_wIPTableCount == 3)
                    penalty += pThis->DoubleKeysToSingleIPOnly3IPsPenalty;
                return(penalty + pThis->DoubleKeysToSingleIPPenalty);
            }
            else
                return(penalty + pThis->DoubleKeysToMergedIPPenalty);
        }
    }
    if (match_Key == DOUBLE_KEYS_TO_SEGMENT_MATCH)
    {
#if CAN_REQUIRE_DOUBLE_GESTURE
        if (pThis->doubleGestureRequired)
        {
            float ipCountAdjust = (float)4.0 / (float)(sw_min(pThis->m_wIPTableCount, 8));   /* Factor ranges from 2.0 to 0.5 for 2 to 8+ IPs */
            return(ipCountAdjust * (penalty + pThis->DoubleKeysToSegmentPenalty));
        }
        else
#endif
            return(penalty + pThis->DoubleKeysToSegmentPenalty);
    }
    if (match_Key == DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH)
    {
        if (ipDat->m_DoubleIPIndex > 0)         /* If multiple IPs were generated from a DoubleLetter gesture, then assess no penalties */
        {
            if (pThis->ipIndex <= (pThis->m_wIPTableCount - 1))   /* Check that final IP was from same gesture */
            {
                if (pThis->m_aIPTable[pThis->ipIndex]->m_DoubleIPIndex == ipDat->m_DoubleIPIndex)
                    return (penalty);
            }   /* Otherwise, calculate and return standard Multiple-IP match penalty */
        }
        if (isSuffix)
        {
            if (!pThis->multipleIPsTotal)          /* Only assess certain penalties for first Multiple IPs match encountered in word */
            {
                penalty += DOUBLE_KEYS_TO_MULTIPLE_IPS_SFX;
                if (pThis->m_wIPTableCount == 2)
                    penalty += MULTIPLE_IPS_ONLY_2_IPS_IN_TABLE_SFX;
                else if (pThis->m_wIPTableCount == 3)
                    penalty += MULTIPLE_IPS_ONLY_3_IPS_IN_TABLE_SFX;
            }
            if (pThis->ipIndex == pThis->multipleIPCount)     /* Must have started with PenUp IP */
                penalty += MULTIPLE_IPS_INCLUDE_PEN_UP_SFX;
            if (pThis->multipleIPCount == 1)
                penalty += MULTIPLE_IPS_ONLY_2_IPS_SFX;
        }
        else
        {
            if (!pThis->multipleIPsTotal)          /* Only assess certain penalties for first Multiple IPs match encountered */
            {
                penalty += DOUBLE_KEYS_TO_MULTIPLE_IPS;
                /* Increase penalty when small number of IPs to avoid "ee" instead of "we", etc. */
                if (pThis->m_wIPTableCount == 2)
                    penalty += MULTIPLE_IPS_ONLY_2_IPS_IN_TABLE;
                else if (pThis->m_wIPTableCount == 3)
                    penalty += MULTIPLE_IPS_ONLY_3_IPS_IN_TABLE;
            }
            if (pThis->ipIndex == (pThis->m_wIPTableCount - 1))   /* Must have ended with PenUp IP */
            {
                penalty += MULTIPLE_IPS_INCLUDE_PEN_UP;
                /* Additional penalty if PenUp is NOT also included in the DoubleLetter gesture */
                if (ipDat->m_DoubleIPIndex > 0)         /* If multiple IPs were generated from a DoubleLetter gesture */
                {
                    if (pThis->ipPenUp->m_DoubleIPIndex != ipDat->m_DoubleIPIndex)     /* If PenUp was NOT included in gesture... */
                    {
                        if (pThis->ipPenUp->m_IPType == PenUp)                         /* ... and it was not a SoftUp... */
                            penalty += PEN_UP_NOT_IN_GESTURE;                   /*   then assess additional penalties. */
                    }
                }
            }
            if (pThis->ipIndex == pThis->multipleIPCount)     /* Must have started with PenDown IP */
            {
                penalty += MULTIPLE_IPS_INCLUDE_PEN_DOWN;
                if (pThis->ipPenDown->m_DoubleIPIndex <= 0)                    /* If PenDown was NOT included in gesture... */
                {
                    if (pThis->m_aIPTable[1]->m_DoubleIPIndex > 0)     /* ...but one or more included IPs were, */
                    {
                        if (pThis->ipPenDown->m_IPType == PenDown)             /* ... and it was not a SoftDown... */
                            penalty += PEN_DOWN_NOT_IN_GESTURE;         /*   then assess additional penalties. */
                    }
                }
            }
            if (pThis->multipleIPCount == 1)
                penalty += MULTIPLE_IPS_ONLY_2_IPS;
            else if (pThis->multipleIPCount > 3)
                penalty += EXCESS_MULTIPLE_IPS_PENALTY;
        }
        pThis->multipleIPsTotal += pThis->multipleIPCount + 1;
        /* Don't kill a candidate just for a Multiple-IPs match - constrain total penalty assessed */
        {
            float   penaltyLimit;
            if (pThis->forward)
                penaltyLimit = pThis->maxCandidateIPPenaltyBase * (float)0.7;    /* was (3 * pThis->maxCandidateIPPenaltyBase) / 4; */
            else
                penaltyLimit = pThis->maxSuffixCandidatePenalty * (float)0.7;      /* was (3 * pThis->maxSuffixCandidatePenalty) / 4; */
            if (penalty > penaltyLimit)
                penalty = penaltyLimit;
        }
        return(penalty);
    }
    if (match_Key == MULTIPLE_KEYS_TO_MERGED_IP_MATCH)
        return(penalty + MULTIPLE_KEYS_TO_MERGED_IP);
    /* Location of Transposition penalties recorded in keyFlags[] entries, but may be over-written */
    /* Actual count of errors recorded in transposeCount and omissionCount/omitCount.  Penalties assessed at end of scoring process. */
    if (match_Key >= NEXT_KEY_IP_MATCH) /*((match_Key == CURRENT_KEY_TRANSPOSED) || (match_Key == OMIT_CURRENT_KEY) || (match_Key == OMIT_CURRENT_KEY_NOW) || (match_Key == OMIT_TRANSPOSED_KEY)) */
        return(penalty);

    if (!advance_IP || (p_IPType == Exit) || (p_IPType == Entry) || (p_IPType == Multiple) || (p_IPType == PathDivision))
    {
        if (match_Key != NO_PATTERN_MATCH)
        {
            DebugAssert(penalty == pThis->oddPathPenalty);
            return(penalty);
        }
        return((float)0.0);
    }
    {
        switch (p_IPType)
        {
        case PenDown:
        case PenUp:
        case Angle:
        case PauseAngle:        /* Convert skippedIPs to float and add fractional skipped IP for PauseAngle ??? */
            *IPskipPenalty = ipDat->m_fSkipPenalty;
            setlastSkipPosIndex = _TRUE;
            if (_SWCSearchDB_IsRequiredIP(ipDat))
                (*skippedIPs)++;
            break;
        /* SavedCodeSegments/SearchDB.cpp/92 */
        case SoftDown:
            *IPskipPenalty = ipDat->m_fSkipPenalty;
            break;
        case SoftUp:
            if (ipDat->m_DoubleIPIndex == 0)
                *IPskipPenalty = ipDat->m_fSkipPenalty;
            else
                *IPskipPenalty = SKIPPED_DOUBLE_IP_SOFT_UP;
            break;
        case Pause:             /* Convert skippedIPs to float and add fractional skipped IP for Pause ??? */
            *IPskipPenalty = ipDat->m_fSkipPenalty;
            break;
        default:
            break;
        }                       /*lint !e788 */
    }
    if (setlastSkipPosIndex)        /* Record position of last skipped IP */
    {
        pThis->lastSkipPosIndex = ipDat->m_IPPosIndex;
    }
    return(penalty + *IPskipPenalty);
}

void ET9FARCALL _SWCSearchDB_ResetDoubleIndices(_SWCSearchDB *pThis, SBYTE2 restartPos)
{
    /* Reset nextDoubleKeyIndex to proper starting value */
    for (pThis->nextDoubleKeyIndex = 0; (pThis->nextDoubleKeyIndex < pThis->doubleKeyCount) && (pThis->doubleKeyIndices[pThis->nextDoubleKeyIndex] < restartPos); pThis->nextDoubleKeyIndex++)
        ;
}

void ET9FARCALL _SWCSearchDB_SetDoubleIndicesFromKeyRepeats(_SWCSearchDB *pThis, BYTE1 *keyRepeats, CPOS length)
{
    SBYTE2 i;
#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis)
        pThis->bBreakHere = _TRUE;
#endif
    pThis->doubleKeyCount = pThis->repeatedKeyCount = 0;
    for (i = 0; (i < length); i++)
    {
        if (keyRepeats[i] > 0)
        {
            pThis->doubleKeyIndices[pThis->doubleKeyCount] = i;
        }
    }
    /* Increase maxCandidateIPPenalty if word has large number of double letters */
    if (pThis->doubleKeyCount > 2)
        pThis->maxCandidateIPPenalty = pThis->maxCandidateIPPenaltyBase + ((float)(pThis->doubleKeyCount - 2) * pThis->ExcessDoubleKeysPenaltyAllowance);
    else
        pThis->maxCandidateIPPenalty = pThis->maxCandidateIPPenaltyBase;
    pThis->doubleKeyIndices[pThis->doubleKeyCount] = -2;      /* Set final + 1 to invalid value to avoid false-positive testing */
    pThis->nextDoubleKeyIndex = 0;             /* Initialize for start of matching process */
}   /* SetDoubleIndicesFromKeyRepeats() */

static void _SWCSearchDB_ApplyShiftGestures(_SWCSearchDB *pThis, _SWWord *dbWord, ET9FLOAT *shiftPenalty)
{
    ET9BOOL shiftFirst = _FALSE;
    SBYTE2 shiftLater = 0;

    /* Apply any detected Shift gestures to the appropriate letters of the word. */
    if (_ET9_LanguageSpecific_ApplyShifting(_ET9AWSP_DATA->pLingInfo, dbWord->pWord) &&
        (_ET9AWSP_DATA->pLingInfo->pLingCmnInfo->Base.pWordSymbInfo->Private.bStateShiftGesture ||
         _ET9AWSP_DATA->pLingInfo->pLingCmnInfo->Base.pWordSymbInfo->Private.bStateCapsGesture))
    {
        if (!pThis->m_SearchShiftAll)
        {
            if (_ET9AWSP_DATA->pLingInfo->pLingCmnInfo->Base.pWordSymbInfo->Private.bStateShiftGesture &&
                (((pThis->m_SearchShiftLocCount > 0) || pThis->m_bShiftFirstLetter) && (dbWord->textLen > 0)))     /* Apply any shiftPos[] shift gestures detected (unless this is a NULL word) */
            {
                CPOS shiftKeyPos = 0;
                SBYTE2 gest = 0;
                CPOS charOffset = 0;
                CPOS nextOmissionEvent = 0;
                CPOS nextOmitPos = -1;
                CPOS nextOmitCount = 0;
                CPOS keyPos;

                if (pThis->m_SearchShiftLocCount > 0)
                {
                    _ET9AWSP_DATA->pLingInfo->pLingCmnInfo->Private.__SPATH_Status.bHasShiftGesture = 1;
                }

                dbWord->matchPosIndex[dbWord->length] = 0;      /* Set terminating test value */
                if (pThis->finalScoringPass && pThis->m_bShiftFirstLetter)            /* Shift first letter if flag was set */
                {
                    BYTE2 shiftLet = _ET9SymToUpper(dbWord->externalText[0], _ET9AWSP_DATA->dwSwypeWordLocale);
                    dbWord->externalText[0] = shiftLet;
                }
                /* Identify which letters should be upper-cased */
                /* TODO(CAK): Confirm this Fix for MGD */
                if (nextOmissionEvent < pThis->omissionCount)
                {
                    nextOmitPos = pThis->omitKeys[nextOmissionEvent];
                    nextOmitCount = pThis->omitCounts[nextOmissionEvent++];
                }
                for (keyPos = 0; (keyPos < pThis->keySeqLength) && (gest < pThis->m_SearchShiftLocCount); keyPos++)
                {
                    /* Check whether key(s) were omitted from current location, and if so, adjust character offset */
                    ET9BOOL firstCharAfterOmittedChar = _FALSE;
                    if (keyPos == nextOmitPos)
                    {
                        charOffset += nextOmitCount;
                        firstCharAfterOmittedChar = _TRUE;
                        if (nextOmissionEvent < pThis->omissionCount)
                        {
                            nextOmitPos = pThis->omitKeys[nextOmissionEvent];
                            nextOmitCount = pThis->omitCounts[nextOmissionEvent++];
                        }
                        else
                            nextOmitPos = -1;
                    }
                    if ((dbWord->matchPosIndex[keyPos] <= pThis->m_SearchShiftPos[gest]) &&
                        ((dbWord->matchPosIndex[keyPos + 1] > pThis->m_SearchShiftPos[gest]) || (!dbWord->matchPosIndex[keyPos + 1])))
                    {
                        shiftKeyPos = charOffset + _SWCSearchDB_findTransposedCharOffset(pThis, keyPos, pThis->keySeqLength);
                        /* Only shift character in final scoring pass */
                        if (pThis->finalScoringPass)
                        {
                            BYTE2 shiftLet;
                            /* word text may be less than word keys (e.g. French 1 letter words), ensure we don't overrun */
                            if (shiftKeyPos >= dbWord->textLen)
                                shiftKeyPos = dbWord->textLen - 1;
                            shiftLet = _ET9SymToUpper(dbWord->externalText[shiftKeyPos], _ET9AWSP_DATA->dwSwypeWordLocale);
                            dbWord->externalText[shiftKeyPos] = shiftLet;
                        }
                        if (shiftKeyPos == 0)
                            shiftFirst = _TRUE;
                        else if (!firstCharAfterOmittedChar)
                            shiftLater++;
                        gest++;
                    }
                    charOffset += pThis->m_keyRepeats[keyPos] + 1;
                }
                /* SavedCodeSegments/295 - Old Shift anomaly logic */
                if ((shiftLater && !pThis->m_SearchShiftAll) || (shiftFirst && !pThis->m_SearchFirstLetterShiftGesture))
                {
                    if (!shiftFirst)
                    {
                        dbWord->shiftAnomaly = _TRUE;
                        if (shiftLater == 1)        /* If only one letter is shifted */
                        {
                            if (shiftKeyPos == (dbWord->textLen - 1))   /* If ONLY final key is shifted, user may have just over-shot final key */
                            {
                                *shiftPenalty = SHIFT_PENALTY_5;         /* ilasT */
                            }
                            else
                            {
                                if (pThis->m_SearchFirstLetterShiftGesture)
                                    *shiftPenalty = SHIFT_PENALTY_2A;     /* wRong (figuratively speaking - path goes from PenDown directly to Exit) */
                                else        /* Path has intervening IP or curvature prior to Exit */
                                {
                                    if ((dbWord->externalText[0] == 'i') && _ET9SymIsUpper(dbWord->externalText[1], _ET9AWSP_DATA->dwSwypeWordLocale))
                                    {
                                        dbWord->shiftAnomaly = _FALSE;
                                        *shiftPenalty = SHIFT_PENALTY_2C;     /* iTunes, iPod, etc. */
                                    }
                                    else
                                        *shiftPenalty = SHIFT_PENALTY_2B;     /* Single non-initial shifted letter */
                                }
                            }
                        }
                        else if (shiftLater == (dbWord->textLen - 1))
                            *shiftPenalty = SHIFT_PENALTY_2B;     /* iPAQ */
                        else
                            *shiftPenalty = SHIFT_PENALTY_4;     /* iWHat... */
                    }
                    /* else if first letter is shifted AND... */
                    else if (shiftLater < (dbWord->textLen - 1))   /* If user has manually shifted ALL letters - no anomaly */
                    {
                        if (!pThis->m_SearchFirstLetterShiftGesture)      /* If user did not appear to intend to shift the first letter */
                        {
                            dbWord->shiftAnomaly = _TRUE;
                            *shiftPenalty = SHIFT_PENALTY_0;                     /* e.g. SMS */
                        }
                        if (shiftLater == (dbWord->textLen - 2))   /* Only one non-initial letter NOT shifted */
                        {
                            /* Lower penalty if unshifted character is the final character */
                            if (_ET9SymIsLower(dbWord->externalText[dbWord->textLen - 1], _ET9AWSP_DATA->dwSwypeWordLocale))
                                *shiftPenalty += SHIFT_PENALTY_3A;            /* e.g. ICBMs, PCs */
                            /* Lower penalty if unshifted character is the second character of at least 5 */
                            else if ((dbWord->textLen >= 5) && _ET9SymIsLower(dbWord->externalText[1], _ET9AWSP_DATA->dwSwypeWordLocale))
                                *shiftPenalty += SHIFT_PENALTY_3B;            /* e.g. McDONALD */
                            else
                            {
                                dbWord->shiftAnomaly = _TRUE;
                                *shiftPenalty += SHIFT_PENALTY_3D;            /* e.g. MCDoNALD... */
                            }
                        }
                        else if (shiftLater == 1)                        /* Only one non-initial letter shifted */
                        {
                            /* Lower penalty if shifted character is the third character of at least 5 */
                            if ((dbWord->textLen >= 5) && _ET9SymIsUpper(dbWord->externalText[2], _ET9AWSP_DATA->dwSwypeWordLocale))
                                *shiftPenalty += SHIFT_PENALTY_3C;       /* e.g. McDonald */
                            else
                            {
                                dbWord->shiftAnomaly = _TRUE;
                                *shiftPenalty += SHIFT_PENALTY_3D;            /* e.g. McdoNald... */
                            }
                        }
                        else
                        {
                            dbWord->shiftAnomaly = _TRUE;
                            *shiftPenalty += SHIFT_PENALTY_1;         /* McDoNALd */
                        }
                    }
                }
            }
        }
        else if (_ET9AWSP_DATA->pLingInfo->pLingCmnInfo->Base.pWordSymbInfo->Private.bStateCapsGesture &&
                 pThis->finalScoringPass)   /* Upper-case everything if CAP-LOCK gesture detected */
        {
            CPOS shiftKeyPos;
            for (shiftKeyPos = 0; shiftKeyPos < dbWord->textLen; shiftKeyPos++)
            {
                BYTE2 shiftLet = _ET9SymToUpper(dbWord->externalText[shiftKeyPos], _ET9AWSP_DATA->dwSwypeWordLocale);
                dbWord->externalText[shiftKeyPos] = shiftLet;
            }
        }
    }
}

void ET9FARCALL _SWCSearchDB_FailCandidate(_SWCSearchDB *pThis)
{
    ET9FLOAT shiftPenalty = 0.0f;
    _SWCSearchDB_ApplyShiftGestures(pThis, pThis->thisWord, &shiftPenalty);
    pThis->isCandidate = _FALSE;
    pThis->exitLoop = _TRUE;
#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis)
        pThis->bBreakHere = _TRUE;
#endif
}

ET9BOOL ET9FARCALL _SWCSearchDB_SwapKeysOKFromKeyRepeats(_SWCSearchDB *pThis, SBYTE2 currentKeyIndex, SBYTE2 keyLimit, ET9BOOL *swapPrevOK, ET9BOOL *swapNextOK, ET9BOOL *omitKeyOK)
{
    ET9BOOL    swapPrevAllowed, swapNextAllowed;
    ET9BOOL    key_1_Double, key_2_Double, key_3_Double, key_4_Double, key_5_Double;
    BYTE1 key_1, key_2, key_3, key_4, key_5;
    *swapPrevOK = *swapNextOK = *omitKeyOK = _FALSE;
    if (currentKeyIndex < 1)
        return(_FALSE);
    if (currentKeyIndex == 1)
    {
        key_1 = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
        key_1_Double = _FALSE;
    }
    else
    {
        key_1 = pThis->keys[currentKeyIndex - 2];
        key_1_Double = (pThis->m_keyRepeats[currentKeyIndex - 2] > 0);
    }
    key_2 = pThis->keys[currentKeyIndex - 1];
    key_2_Double = (pThis->m_keyRepeats[currentKeyIndex - 1] > 0);
    key_3 = pThis->keys[currentKeyIndex];
    key_3_Double = (pThis->m_keyRepeats[currentKeyIndex] > 0);
    if (keyLimit > (currentKeyIndex + 1))
    {
        key_4 = pThis->keys[currentKeyIndex + 1];
        key_4_Double = (pThis->m_keyRepeats[currentKeyIndex + 1] > 0);
    }
    else
    {
        key_4 = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
        key_4_Double = _FALSE;
    }
    if (keyLimit > (currentKeyIndex + 2))
    {
        key_5 = pThis->keys[currentKeyIndex + 2];
        key_5_Double = (pThis->m_keyRepeats[currentKeyIndex + 2] > 0);
    }
    else
    {
        key_5 = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
        key_5_Double = _FALSE;
    }
    /* Key 3 may be omitted even when key_2 == key_4.  This case is detected as a "false" double key, and is not processed as an */
    /* actual double key.  This allows the user to enter a word such as "agnosticism" to be identified when the user's path */
    /* does not come close enough to the "c" and the "c" needs to be omitted. */
    /**omitKeyOK = (key_2 != key_3);           // Shouldn't delete 2nd half of double key "after the fact..." */
    *omitKeyOK = _TRUE;                         /* With MGD, double key can no longer be split */
    if (pThis->transpositionLevel == NO_TRANSPOSITIONS)
        return(_FALSE);
    else if (pThis->transpositionLevel == VOWELS_ONLY)
    {
        swapPrevAllowed = swapNextAllowed = _SWCSearchDB_isVowelKey(pThis, key_3, _TRUE) && !key_3_Double;
        swapPrevAllowed = (swapPrevAllowed && _SWCSearchDB_isVowelKey(pThis, key_2, _TRUE) && !key_2_Double);
        swapNextAllowed = (swapNextAllowed && _SWCSearchDB_isVowelKey(pThis, key_4, _TRUE) && !key_4_Double);
    }
    else
    {
        swapPrevAllowed = !key_2_Double && !key_3_Double;
        swapNextAllowed = !key_3_Double && !key_4_Double;
    }
    {
        ET9BOOL check1 = ((key_1 != key_3) && (key_1 != SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)));
        ET9BOOL check2 = (key_2 != key_4);
        ET9BOOL check3 = ((key_3 != key_5) && (key_4 != SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)));
        *swapPrevOK = (check1 && check2 && swapPrevAllowed);
        *swapNextOK = (check2 && check3 && swapNextAllowed);
    }
    return(*swapPrevOK || *swapNextOK);
}

/* Determine whether currently determined matching position for key1 (of matching type matchKey, at fixed index *matchPosIndex) is consistent with the input */
/* path and the previously determined position for lastKey.  If not, see if an alternate and consistent matching location can be found (based on */
/* matching type matchKey). */
ET9BOOL ET9FARCALL _SWCSearchDB_MatchLocOK(_SWCSearchDB *pThis, SBYTE2 *matchPosIndex, float *mslopeDifFactor, float *dslopeDifFactor)
{
    ET9BOOL retVal = _FALSE;
    BYTE1   key_2 = pThis->key2;               /* Init assuming suffixVectorCheck will be false */
    ET9BOOL lookForAltMatchPos = (ET9BOOL)((pThis->keyIndex > 1) && (!pThis->forward || (pThis->keyIndex < pThis->keySeqLength)));   /* No alternate match position for PenUp or PenDown */
    ET9BOOL isSegmentMatch = _FALSE;
    ET9BOOL saveAltMatchPos = _TRUE;
    ET9BOOL suffixVectorCheck = _FALSE;
    _SWPoint matchKeyPosDummy;
    int indexM1, indexM2;
    SBYTE2 matchKeyPosIndex3 = 0;      /* Assume this is not a segment match */
    SBYTE2 altMatchKey2PosIndex = 0;
    SBYTE2 altMatchKeyPosIndex2 = 0;

#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis)
        pThis->bBreakHere = _TRUE;
#endif
    pThis->altMatchKeyHasSegmentMatch = _FALSE;
    pThis->altMatchKeyType = NO_PATTERN_MATCH;
    indexM1 = pThis->keyIndex - 2;
    indexM2 = pThis->keyIndex - 3;
    /* If we are scoring a suffix, check whether the previous match was a segment match.  If so, set matchKeyPosIndex3 and altMatchKey2PosIndex */
    /*   so that vector adjustment can be made to slopeFactor if needed */
    if (!pThis->forward && (indexM2 >= 0))
    {
        if ((pThis->matchKeyType[indexM1] == THIS_SEGMENT_MATCH) || (pThis->matchKeyType[indexM1] == DOUBLE_KEYS_TO_SEGMENT_MATCH))
        {
            matchKeyPosIndex3 = altMatchKey2PosIndex = matchPosIndex[indexM2];
            suffixVectorCheck = _TRUE;
            key_2 = pThis->keys[indexM2];         /* Perform vector check using same keys that would have been used for this slopeFactor when moving forward */
        }
    }
    *mslopeDifFactor = *dslopeDifFactor = DEFAULT_SLOPE_FACTOR;       /* Init to default value */
    /* Make sure current match and previous match are consistent with input path */
    if (pThis->matchKey != NO_PATTERN_MATCH)       /* Wait till current key actually matched */
    {
        retVal = _TRUE;
        pThis->altMatchKeyPosIndex = pThis->altMatchKeyLocIndex = 0;      /* Assume no alternate matching location to check */
        switch (pThis->matchKey)
        {
        case IP_MATCH:
        case DOUBLE_KEYS_TO_SINGLE_IP_MATCH:
        case MULTIPLE_KEYS_TO_MERGED_IP_MATCH:              /* Separate matching locs for each key? Based on closest path point near/within gesture? */
            pThis->matchKeyPos = pThis->ipData->m_IPLocation;
            pThis->matchKeyPosIndex = pThis->ipData->m_IPPosIndex;
            if (pThis->forward)
            {
                pThis->matchKeyLocIndex = pThis->ipData->m_FixedIndexIn;
                pThis->matchKeyLocExitIndex = pThis->ipData->m_FixedIndexOut;
            }
            else
            {
                pThis->matchKeyLocIndex = pThis->ipData->m_FixedIndexOut;
                pThis->matchKeyLocExitIndex = pThis->ipData->m_FixedIndexIn;
            }
            pThis->matchKeyLoc = _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->matchKeyLocIndex);
            /* No alternate match position for PenUp or PenDown */
            if (lookForAltMatchPos && (pThis->matchKey != MULTIPLE_KEYS_TO_MERGED_IP_MATCH))
            {
                if (pThis->key1Seg1)
                {
                    ET9BOOL    useSegmentMatch;
                    pThis->altMatchKeyPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key1, &pThis->altMatchKeyPos, &pThis->altMatchKeyLoc, &pThis->altMatchKeyLocIndex);
                    pThis->altMatchKeyLocExitIndex = pThis->altMatchKeyLocIndex;
                    pThis->altMatchKeyType = (pThis->matchKey == DOUBLE_KEYS_TO_SINGLE_IP_MATCH) ? DOUBLE_KEYS_TO_SEGMENT_MATCH : SEGMENT_MATCH;
                    pThis->altMatchKeyRawDist = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg1Data, pThis->key1);
                    pThis->altMatchKeyRawScore = pThis->key1Seg1;
                    pThis->altMatchKeyWeightSum = _SWCSearchDB_GetSegmentMatchWeight(pThis, pThis->seg1Data, pThis->key1);
                    pThis->altMatchKeyHasSegmentMatch = _TRUE;
                    /* Do a sanity-check based on the path distances from last match position (or Entry IP, if applicable) to the segment match location */
                    /*   and to the IP match location.  If the distance to the IP match location is excessive, then use the segment match as the */
                    /*   primary match location and set matchKey to THIS_SEGMENT_MATCH */
                    useSegmentMatch = (ET9BOOL)(pThis->key2Seg1 || pThis->key2IP1 || pThis->key3Seg1 || pThis->key3IP1);     /* Check if any indication of other matches on this segment */
                    if (useSegmentMatch)
                    {
                        SBYTE2  exitXPos, entryPosIndex, startPosIndex, pathToSegmentMatch, pathToIPMatch, differenceThreshold;
                        if (_SWCSearchDB_PathExitsKeyboard(pThis, pThis->lastMatchKeyPosIndex, pThis->matchKeyPosIndex, &exitXPos, &entryPosIndex))
                            startPosIndex = entryPosIndex;
                        else
                            startPosIndex = pThis->lastMatchKeyPosIndex;
                        /* Make sure we are not dealing with an out-of-order segment match that precedes the preceding already-matched key */
                        if (_SWCSearchDB_PointsInSequence(pThis, startPosIndex, pThis->altMatchKeyPosIndex) &&
                            _SWCSearchDB_PointsInSequence(pThis, startPosIndex, pThis->matchKeyPosIndex))
                        {
                            pathToSegmentMatch = _SWCSearchDB_GetZ1PathLength(pThis, startPosIndex, pThis->altMatchKeyPosIndex);
                            pathToIPMatch = _SWCSearchDB_GetZ1PathLength(pThis, startPosIndex, pThis->matchKeyPosIndex);
                            /* Use distance difference threshold defined as a multiple of the current Angle IP threshold (the largest of the applicable types) */
                            differenceThreshold = (SBYTE2)(PATH_DIFFERENCE_FACTOR * pThis->m_backend->pIPTable->IPthreshold8[Angle][1] / 8);
                            useSegmentMatch = (ET9BOOL)(pathToIPMatch > (pathToSegmentMatch + differenceThreshold));
                        }
                        else
                            useSegmentMatch = _FALSE;
                    }
                    if (useSegmentMatch)        /* If path to IP match is excessively long, use segment match */
                    {
                        SBYTE2 swapVal;
                        _SWPoint swapPoint;
                        pThis->altMatchKeyType = pThis->matchKey;
                        pThis->altMatchKeyRawDist = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);
                        pThis->altMatchKeyRawScore = pThis->key1IP1;
                        pThis->altMatchKeyWeightSum = pThis->ipData->m_fIPWeight;
                        pThis->altMatchKeyHasSegmentMatch = _FALSE;
                        if (pThis->matchKey == DOUBLE_KEYS_TO_SINGLE_IP_MATCH)
                        {
                            pThis->matchKey = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                        }
                        else
                        {
                            pThis->matchKey = THIS_SEGMENT_MATCH;
                        }
                        /* Swap all "regular" and "alt" match info */
                        swapVal = pThis->matchKeyPosIndex;
                        pThis->matchKeyPosIndex = pThis->altMatchKeyPosIndex;
                        pThis->altMatchKeyPosIndex = swapVal;
                        swapVal = pThis->matchKeyLocIndex;
                        pThis->matchKeyLocIndex = pThis->altMatchKeyLocIndex;
                        pThis->altMatchKeyLocIndex = swapVal;
                        swapVal = pThis->matchKeyLocExitIndex;
                        pThis->matchKeyLocExitIndex = pThis->altMatchKeyLocExitIndex;
                        pThis->altMatchKeyLocExitIndex = swapVal;
                        swapPoint = pThis->matchKeyPos;
                        pThis->matchKeyPos = pThis->altMatchKeyPos;
                        pThis->altMatchKeyPos = swapPoint;
                        swapPoint = pThis->matchKeyLoc;
                        pThis->matchKeyLoc = pThis->altMatchKeyLoc;
                        pThis->altMatchKeyLoc = swapPoint;
                        isSegmentMatch = _TRUE;
                        /* Set matchKeyPosIndex3 for segment match */
                        if (pThis->forward)
                        {
                            SBYTE2 multipleCount = (pThis->key2IsDoubleKey) ? pThis->ipData->m_ForwardMultipleCount : 0;
                            if (multipleCount > 0)
                            {
                                SWCIPTableRow *ipCheck1, *ipCheck2;
                                SBYTE2 checkIndex1 = multipleCount / 2;
                                ipCheck1 = pThis->m_aIPTable[checkIndex1];
                                ipCheck2 = pThis->m_aIPTable[checkIndex1 + 1];
                                matchKeyPosIndex3 = (ipCheck1->m_IPPosIndex + ipCheck2->m_IPPosIndex) / 2;
                            }
                            else if (pThis->key2IP1 && (!pThis->key3IP1 || !pThis->key2Seg1 || pThis->key3Seg2 || pThis->key3IP2 || (pThis->key2IP1 < pThis->key2Seg1) || (pThis->key2IP1 < pThis->key3IP1)))
                            {
                                matchKeyPosIndex3 = pThis->ipData->m_IPPosIndex;
                            }
                            else if (pThis->key2Seg1)
                            {
                                matchKeyPosIndex3 = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key2, &matchKeyPosDummy, &pThis->matchKeyLoc3, &pThis->matchKeyLocIndex3);
                            }
                        }
                    }
                    else if (pThis->forward)       /* Proceed with IP match.  Set altMatchKey2PosIndex if we are scoring a word (not a suffix) */
                    {
                        if (pThis->key2IP1)
                        {   /* Set altMatchKey2PosIndex for scoring alternate segment match in case needed */
                            altMatchKey2PosIndex = pThis->matchKeyPosIndex;
                        }
                        else if (pThis->key2Seg1)
                        {
                            altMatchKey2PosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key2, &matchKeyPosDummy, &pThis->altMatchKeyLoc3, &pThis->altMatchKeyLocIndex3);
                            /* Make sure matching position for following key is in correct path order */
                            if (altMatchKey2PosIndex <= pThis->altMatchKeyPosIndex)
                                altMatchKey2PosIndex = 0;
                        }
                    }
                }
                if (pThis->key1Seg2 && (!pThis->key1Seg1 || pThis->thisKeyCheckAlternateMatches))
                {
                    _SWPoint altMatchKeyPos2;
                    altMatchKeyPosIndex2 = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg2Data, pThis->key1, &altMatchKeyPos2, &pThis->altMatchKeyLoc2, &pThis->altMatchKeyLocIndex2);
                    if (!pThis->key1Seg1)
                    {
                        saveAltMatchPos = _FALSE;
                        pThis->altMatchKeyPosIndex = altMatchKeyPosIndex2;
                        pThis->altMatchKeyPos = altMatchKeyPos2;
                        pThis->altMatchKeyLoc = pThis->altMatchKeyLoc2;
                        pThis->altMatchKeyLocIndex = pThis->altMatchKeyLocExitIndex = pThis->altMatchKeyLocIndex2;
                        pThis->altMatchKeyType = (pThis->matchKey == DOUBLE_KEYS_TO_SINGLE_IP_MATCH) ? DOUBLE_KEYS_TO_SEGMENT_MATCH : SEGMENT_MATCH;
                        pThis->altMatchKeyRawDist = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg2Data, pThis->key1);
                        pThis->altMatchKeyRawScore = pThis->key1Seg2;
                        pThis->altMatchKeyWeightSum = _SWCSearchDB_GetSegmentMatchWeight(pThis, pThis->seg2Data, pThis->key1);
                        pThis->altMatchKeyHasSegmentMatch = _TRUE;
                    }
                }
            }
            break;

        case DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH:
            /* matchKeyPosIndex, etc., already set in CheckMultipleIPsMatch() */
            /* Save first IP position as alternate match loc */
            if (!pThis->key1Seg1)
            {
                pThis->altMatchKeyPosIndex = pThis->altMatchKeyLocIndex = pThis->altMatchKeyLocExitIndex = pThis->matchKeyLocIndex;
                pThis->altMatchKeyPos = pThis->altMatchKeyLoc = pThis->matchKeyLoc;
                pThis->altMatchKeyType = DOUBLE_KEYS_TO_SINGLE_IP_MATCH;
                pThis->altMatchKeyRawDist = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);
                pThis->altMatchKeyRawScore = pThis->key1IP1;
                pThis->altMatchKeyWeightSum = pThis->ipData->m_fIPWeight;
                pThis->altMatchKeyHasSegmentMatch = _FALSE;
            }
            /* lastKey, lastMatchKeyLoc and lastMatchKeyPosIndex updated after return from CheckKeyMatches() */
            break;

        /* SavedCodeSegments/SearchDB.cpp/93 */
        case THIS_SEGMENT_MATCH:
        case DOUBLE_KEYS_TO_SEGMENT_MATCH:
            if (pThis->seg1Data == NULL)
            {
                _SWCSearchDB_FailCandidate(pThis);
                return(_FALSE);
            }
            isSegmentMatch = _TRUE;
            pThis->matchKeyPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key1, &pThis->matchKeyPos, &pThis->matchKeyLoc, &pThis->matchKeyLocIndex);
            if (pThis->matchKeyPosIndex == IPT_NO_MATCH)
            {
                /*_SWCSearchDB_FailCandidate(pThis); ?? */
                return(_FALSE);
            }

            pThis->matchKeyLocExitIndex = pThis->matchKeyLocIndex;
            if (pThis->forward)        /* Set matchKeyPosIndex3 to next "expected" match location if we are scoring a word (not a suffix) */
            {
                if (pThis->key2IP1 && (!pThis->key3IP1 || !pThis->key2Seg1 || pThis->key3IP2 || (pThis->key2IP1 < pThis->key2Seg1) || (pThis->key2IP1 < pThis->key3IP1)))
                {
                    matchKeyPosIndex3 = pThis->ipData->m_IPPosIndex;
                }
            }
            break;

        case NEXT_SEGMENT_MATCH:
            if (pThis->seg2Data == NULL)
            {
                _SWCSearchDB_FailCandidate(pThis);
                return(_FALSE);
            }
            isSegmentMatch = _TRUE;
            pThis->matchKeyPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg2Data, pThis->key1, &pThis->matchKeyPos, &pThis->matchKeyLoc, &pThis->matchKeyLocIndex);
            if (pThis->matchKeyPosIndex == IPT_NO_MATCH)
            {
                /*_SWCSearchDB_FailCandidate(pThis); ?? */
                return(_FALSE);
            }
            pThis->matchKeyLocExitIndex = pThis->matchKeyLocIndex;
            break;

        default:
            Log(SWLogger_INFO, SWTEXT("Swype Event: %d \r\n"), 417)
            _SWCSearchDB_FailCandidate(pThis);
            return(_FALSE);
        }
        if (_SWCSearchDB_InvalidPosIndex(pThis, pThis->matchKeyPosIndex))
        {
            _SWCSearchDB_FailCandidate(pThis);
            return(_FALSE);
        }
        if (pThis->lastKey < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))   /*  Don't check until second key has been matched */
        {
            /* Compare vector from key to lastKey with slope of line between matched points.  Call */
            /*   params are in reverse order since we are moving backward along the path for suffixes. */
            ET9BOOL dualMatchValid = _FALSE;
            ET9BOOL usedAltMatchKeyLoc = _FALSE;
            ET9BOOL usedAltLastMatchKeyLoc = _FALSE;
            ET9BOOL usedAltLastMatchKeyLocForDual = _FALSE;
            ET9BOOL currentMatchValid = _SWCSearchDB_KeysMatchPoints(pThis, pThis->lastKey, pThis->key1, key_2, isSegmentMatch, (pThis->isSwappedKey || pThis->wasSwappedKey), suffixVectorCheck, pThis->lastMatchKeyLoc, pThis->matchKeyLoc, pThis->lastMatchKeyLocIndex,
                        pThis->matchKeyLocIndex, pThis->lastMatchKeyPos, pThis->matchKeyPos, pThis->lastMatchKeyPosIndex, pThis->matchKeyPosIndex, mslopeDifFactor, matchKeyPosIndex3, pThis->altLastMatchKeyPosIndex, pThis->altMatchKeyPosIndex, altMatchKeyPosIndex2, _TRUE);
            /* If no valid match determined, see if we can find valid match using any combination of alternate match locations */
            if (!currentMatchValid && pThis->altMatchKeyPosIndex && !pThis->isSwappedKey)
            {
                SBYTE2 matchKeyPosIndex3Param = (altMatchKey2PosIndex) ? altMatchKey2PosIndex : matchKeyPosIndex3;
                currentMatchValid = _SWCSearchDB_KeysMatchPoints(pThis, pThis->lastKey, pThis->key1, key_2, pThis->altMatchKeyHasSegmentMatch, pThis->wasSwappedKey, suffixVectorCheck, pThis->lastMatchKeyLoc, pThis->altMatchKeyLoc, pThis->lastMatchKeyLocIndex,
                        pThis->altMatchKeyLocIndex, pThis->lastMatchKeyPos, pThis->altMatchKeyPos, pThis->lastMatchKeyPosIndex, pThis->altMatchKeyPosIndex, mslopeDifFactor, matchKeyPosIndex3Param, pThis->altLastMatchKeyPosIndex, pThis->matchKeyPosIndex, altMatchKeyPosIndex2, _TRUE);
                if (currentMatchValid)
                    usedAltMatchKeyLoc = _TRUE;
            }
            if (!currentMatchValid && pThis->altLastMatchKeyPosIndex && !pThis->wasSwappedKey)
            {
                currentMatchValid = _SWCSearchDB_KeysMatchPoints(pThis, pThis->lastKey, pThis->key1, key_2, isSegmentMatch, pThis->isSwappedKey, suffixVectorCheck, pThis->altLastMatchKeyLoc, pThis->matchKeyLoc, pThis->altLastMatchKeyLocIndex,
                        pThis->matchKeyLocIndex, pThis->altLastMatchKeyPos, pThis->matchKeyPos, pThis->altLastMatchKeyPosIndex, pThis->matchKeyPosIndex, mslopeDifFactor, matchKeyPosIndex3, pThis->lastMatchKeyPosIndex, pThis->altMatchKeyPosIndex, altMatchKeyPosIndex2, _TRUE);
                if (currentMatchValid)
                    usedAltLastMatchKeyLoc = _TRUE;
            }
            if (!currentMatchValid && pThis->altMatchKeyPosIndex  && pThis->altLastMatchKeyPosIndex && !pThis->isSwappedKey && !pThis->wasSwappedKey)
            {
                SBYTE2 matchKeyPosIndex3Param = (altMatchKey2PosIndex) ? altMatchKey2PosIndex : matchKeyPosIndex3;
                currentMatchValid = _SWCSearchDB_KeysMatchPoints(pThis, pThis->lastKey, pThis->key1, key_2, pThis->altMatchKeyHasSegmentMatch, _FALSE, suffixVectorCheck, pThis->altLastMatchKeyLoc, pThis->altMatchKeyLoc, pThis->altLastMatchKeyLocIndex,
                    pThis->altMatchKeyLocIndex, pThis->altLastMatchKeyPos, pThis->altMatchKeyPos, pThis->altLastMatchKeyPosIndex, pThis->altMatchKeyPosIndex, mslopeDifFactor, matchKeyPosIndex3Param, pThis->lastMatchKeyPosIndex, pThis->matchKeyPosIndex, altMatchKeyPosIndex2, _TRUE);
                if (currentMatchValid)
                {
                    usedAltMatchKeyLoc = _TRUE;
                    usedAltLastMatchKeyLoc = _TRUE;
                }
            }
            /* If we just matched the last suffix key with a segment, confirm that it is valid */
            if (pThis->finalKey && !pThis->forward && (pThis->dualMatch != NO_PATTERN_MATCH) && !pThis->dualMatchSet)
            {
                /* Can't test segment vectors since no following key (dual match is for final key of suffix only) */
                dualMatchValid = pThis->dualMatchSet = _SWCSearchDB_KeysMatchPoints(pThis, pThis->lastKey, pThis->key1, key_2, _TRUE, (pThis->isSwappedKey || pThis->wasSwappedKey), suffixVectorCheck, pThis->lastMatchKeyLoc, pThis->dualMatchLoc, pThis->lastMatchKeyLocIndex,
                        pThis->dualMatchLocIndex, pThis->lastMatchKeyPos, pThis->dualMatchPos, pThis->lastMatchKeyPosIndex, pThis->dualMatchPosIndex, dslopeDifFactor, 0, pThis->altLastMatchKeyPosIndex, 0, 0, _TRUE);
                if (!dualMatchValid && pThis->altLastMatchKeyPosIndex && !pThis->wasSwappedKey)
                {
                    dualMatchValid = pThis->dualMatchSet = _SWCSearchDB_KeysMatchPoints(pThis, pThis->lastKey, pThis->key1, key_2, _TRUE, pThis->isSwappedKey, suffixVectorCheck, pThis->altLastMatchKeyLoc, pThis->dualMatchLoc, pThis->altLastMatchKeyLocIndex,
                            pThis->dualMatchLocIndex, pThis->altLastMatchKeyPos, pThis->dualMatchPos, pThis->altLastMatchKeyPosIndex, pThis->dualMatchPosIndex, dslopeDifFactor, 0, pThis->lastMatchKeyPosIndex, 0, 0, _TRUE);
                    if (dualMatchValid)
                        usedAltLastMatchKeyLocForDual = _TRUE;
                }
                if (dualMatchValid && !currentMatchValid)
                {
                    /* Set matchKey to dualMatch to score based on type of segment match detected (i.e. single- or Double-key */
                    pThis->matchKey = pThis->dualMatch;
                    pThis->matchKeyPos = pThis->dualMatchPos;
                    pThis->matchKeyPosIndex = pThis->dualMatchPosIndex;
                    pThis->matchKeyLoc = pThis->dualMatchLoc;
                    pThis->matchKeyLocIndex = pThis->matchKeyLocExitIndex = pThis->dualMatchLocIndex;
                    *mslopeDifFactor = *dslopeDifFactor;
                    usedAltLastMatchKeyLoc = usedAltLastMatchKeyLocForDual;
                }
                else if (!dualMatchValid)
                    pThis->dualMatch = NO_PATTERN_MATCH;       /* Reset dual match since no valid matching identified */
            }
            if (!currentMatchValid && !dualMatchValid)
            {
                pThis->matchKey = NO_PATTERN_MATCH;
                if (!pThis->dualMatchSet && !pThis->forward)
                    pThis->dualMatch = NO_PATTERN_MATCH;
                retVal = _FALSE;
            }
            /* Reset matchKeyLoc, etc. to use final matching point location identified so that lastMatchKeyLoc will be set to the */
            /*   correct location for upcoming attempt to match with following key */
            if (currentMatchValid)
            {
                if (usedAltMatchKeyLoc && saveAltMatchPos)
                {
                    /* Set alternate match location according to match location, in case we revert after following key */
                    SBYTE2 swapMatchKey = pThis->matchKey;
                    ET9BOOL swapIsSegmentMatch = isSegmentMatch;
                    pThis->matchKey = pThis->altMatchKeyType;
                    pThis->altMatchKeyType = swapMatchKey;
                    isSegmentMatch = pThis->altMatchKeyHasSegmentMatch;
                    pThis->altMatchKeyHasSegmentMatch = swapIsSegmentMatch;
                    if (pThis->altMatchKeyHasSegmentMatch)
                    {
                        pThis->altMatchKeyRawDist = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg1Data, pThis->key1);
                        pThis->altMatchKeyRawScore = pThis->key1Seg1;
                        pThis->altMatchKeyWeightSum = _SWCSearchDB_GetSegmentMatchWeight(pThis, pThis->seg1Data, pThis->key1);
                    }
                    else
                    {
                        pThis->altMatchKeyRawDist = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);
                        pThis->altMatchKeyRawScore = pThis->key1IP1;
                        pThis->altMatchKeyWeightSum = pThis->ipData->m_fIPWeight;
                    }
                    {
                        _SWPoint swapPoint = pThis->matchKeyPos;
                        SBYTE2  swapIndex = pThis->matchKeyPosIndex;
                        pThis->matchKeyPos = pThis->altMatchKeyPos;
                        pThis->altMatchKeyPos = swapPoint;
                        pThis->matchKeyPosIndex = pThis->altMatchKeyPosIndex;
                        pThis->altMatchKeyPosIndex = swapIndex;
                        swapPoint = pThis->matchKeyLoc;
                        pThis->matchKeyLoc = pThis->altMatchKeyLoc;
                        pThis->altMatchKeyLoc = swapPoint;
                        swapIndex = pThis->matchKeyLocIndex;
                        pThis->matchKeyLocIndex = pThis->altMatchKeyLocIndex;
                        pThis->altMatchKeyLocIndex = swapIndex;
                        swapIndex = pThis->matchKeyLocExitIndex;
                        pThis->matchKeyLocExitIndex = pThis->altMatchKeyLocExitIndex;
                        pThis->altMatchKeyLocExitIndex = swapIndex;
                    }
                }
                if (usedAltLastMatchKeyLoc)     /* Adjust skipping penalties as needed */
                {
                    if (indexM1 < 0)
                    {
                        _SWCSearchDB_FailCandidate(pThis);
                        return(_FALSE);
                    }
                    /* Update scoring results recorded for key matched to new location */
                    /* Check whether new matching results in a change in skipped IPs */
                    {
                        ET9BOOL addSkippedIP = (ET9BOOL)(((pThis->matchKeyType[indexM1] == IP_MATCH) || (pThis->matchKeyType[indexM1] == DOUBLE_KEYS_TO_SINGLE_IP_MATCH)) &&
                             !_SWCSearchDB_PointsInSequence(pThis, pThis->altLastMatchKeyPosIndex, pThis->lastMatchKeyPosIndex));
                        pThis->matchKeyType[indexM1] = pThis->altLastMatchKeyType;
                        matchPosIndex[indexM1] = pThis->altLastMatchKeyPosIndex;
                        pThis->matchLocExitIndex[indexM1] = pThis->altLastMatchKeyPosIndex;
                        pThis->hasSegmentMatch[indexM1] = pThis->altLastMatchKeyHasSegmentMatch;
                        pThis->rawScoreKey[indexM1] = pThis->altLastMatchKeyRawScore;
                        pThis->rawDistKey[indexM1] = pThis->altLastMatchKeyRawDist;
                        pThis->weightSumKey[indexM1] = pThis->altLastMatchKeyWeightSum;
                        pThis->slopeFactorKey[indexM1] = *mslopeDifFactor;  /* Slope factor to following key is good enough aproximation */

                        /* If preceding match was an IP match that has now been skipped over, adjust penalties */
                        /* TODO: Check for and handle case where an IP turns out to no longer be skipped ("removeSkippedIP" case) */
                        if (addSkippedIP)
                        {
                            float thisPenalty = 0.0;
                            float dummyIPskipPenalty;
                            SWCIPTableRow *ipLastOrig = pThis->m_aIPTable[pThis->ipIndexKey[indexM1]];
                            if (_SWCSearchDB_IsRequiredIP(ipLastOrig))
                            {
                                pThis->skippedIPsCount[indexM1] += 1;     /* Record that this IP was skipped in current matching */
                            }
                            pThis->hasSkippedIPs[indexM1] = _TRUE;
                            pThis->keyIndex--;             /* Decrement prior to GetSkippingPenalty() call so that Diacritic gesture (if any) can be matched */
                            if (pThis->forward)
                            {
                                thisPenalty = _SWCSearchDB_GetSkippingPenalty(pThis, ipLastOrig, NO_PATTERN_MATCH, _TRUE, &pThis->skippedIPsWord, &dummyIPskipPenalty, _FALSE, (float)0.0);
                                pThis->skipPenaltyWord += thisPenalty;
                            }
                            pThis->keyIndex++;             /* Restore following GetSkippingPenalty() call */
                            pThis->keyIndexM1 = pThis->keyIndex - 1;
                            pThis->skipPenaltyKey[indexM1] += thisPenalty;
                        }
                    }
                }
            }
        }
    }
    return(retVal);
}   /* _SWCSearchDB_MatchLocOK() */

/* SavedCodeSegments/279 - CheckMultipleIPsMatchOld() */

ET9BOOL ET9FARCALL _SWCSearchDB_CheckMultipleIPsMatch(_SWCSearchDB *pThis, SBYTE2 fixedLimit)
{
    SWCIPTableRow *ipNext, *ipSeg1 = 0;
    SBYTE2      maxMultipleCount, doubleIPIndex, doubleIPCount;
    SBYTE2      checkIPIndex, IPLimit, IPOffsetLimit;
    ET9BOOL     addAnother, isPathDivision;
    BYTE2       key1IPScore[12] = { 0 }, key2IPScore[12] = { 0 }, key3IPScore[12] = { 0 }, key2SegScore[12] = { 0 }, key3SegScore[12] = { 0 };
    SBYTE2      bestMatch[12] = { 0 };
    _SWPoint    Key1Loc, Key2Loc;
    ET9BOOL findMatchKey2;
    ET9BOOL findMatchKey3;
    ET9BOOL multipleIPsHitLimit;
    SBYTE2 key2DuringIPMatch = 0;
    SBYTE2 key2LastDuringIPMatch = 0;
    SBYTE2 key2DuringSegMatch = 0;
    SBYTE2 key2LastDuringSegMatch = 0;
    SBYTE2 key2DuringIPMatchCount = 0;
    SBYTE2 key3DuringIPMatch = 0;
    SBYTE2 key3LastDuringIPMatch = 0;
    SBYTE2 key3DuringIPMatchCount = 0;
    SBYTE2 key3DuringSegMatch = 0;
    SBYTE2 key3LastDuringSegMatch = 0;
    SBYTE2 key2FollowIPMatch = 0;
    SBYTE2 key2FollowIPMatchMultiple = 0;
    SBYTE2 key2FollowSegMatch = 0;
    SBYTE2 key2FollowIPMatchCount = 0;
    SBYTE2 key3FollowIPMatch = 0;
    SBYTE2 key3LastFollowIPMatch = 0;
    SBYTE2 key3FollowIPMatchMultiple = 0;
    SBYTE2 key3FollowIPMatchCount = 0;
    SBYTE2 key3FollowSegMatch = 0;
    SBYTE2 key3LastFollowSegMatch = 0;
    ET9BOOL isMultiple = _FALSE;
    ET9BOOL wasMultiple;
    ET9BOOL key2MustShareIPs = _FALSE;
    ET9BOOL key3MustShareIPs = _FALSE;
    SBYTE2 firstKey1BestMatch = 0;
    SBYTE2 lastKey1BestMatch = 0;
    SBYTE2 firstKey2BestMatch = 0;
    SBYTE2 lastKey2BestMatch = 0;
    SBYTE2 firstKey3BestMatch = 0;
    SBYTE2 lastKey3BestMatch = 0;
    ET9BOOL bestMatchesInSequence = _TRUE;
    SBYTE2 lastBestMatch = 0;
    SBYTE2 finalKey1Match = 0;
    SBYTE2 ipOffset;
    _SWPoint_Construct_SB2SB2(&Key2Loc, 0, 0);

    /* At minimum, current key must match following IP */
    if (!pThis->key1IP2)
        return(_FALSE);

    key1IPScore[0] = pThis->key1IP1;           /* May be needed for "addAnother" confirmation check */
    SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->key1, &Key1Loc);     /* Get location of key1 */
    if (pThis->key2 != SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))
        SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->key2, &Key2Loc);     /* Get location of key1 */

    findMatchKey2 = (ET9BOOL)((pThis->key2 != SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)) && (!pThis->forward || (pThis->key2Index <= pThis->keyLimitSuffix)));
    findMatchKey3 = (ET9BOOL)((pThis->key3 != SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)) && (!pThis->forward || (pThis->key3Index <= pThis->keyLimitSuffix)));

    multipleIPsHitLimit = _FALSE;
    if (pThis->forward)
    {
        maxMultipleCount = pThis->ipData->m_ForwardMultipleCount;
        /* SavedCodeSegments/SearchDB.cpp/113 */
        if ((pThis->ipLimitSuffix > 0) && (pThis->ipLimitSuffix < pThis->m_wIPTableCount))
        {
            /*pThis->IPLimit = pThis->ipLimitSuffix - 1; */
            IPLimit = pThis->ipLimitSuffix;
        }
        else
            IPLimit = pThis->m_wIPTableCount - 1;
        if ((pThis->ipIndex + maxMultipleCount) > IPLimit)
        {
            maxMultipleCount = IPLimit - pThis->ipIndex;
            multipleIPsHitLimit = _TRUE;
        }
    }
    else
    {
        maxMultipleCount = pThis->ipData->m_BackwardMultipleCount;
        /* SavedCodeSegments/SearchDB.cpp/114 */
        IPLimit = pThis->m_wIPTableCount - 1;
        if ((pThis->ipIndex + maxMultipleCount) > IPLimit)
        {
            maxMultipleCount = IPLimit - pThis->ipIndex;
            multipleIPsHitLimit = _TRUE;
        }
    }
    /* SavedCodeSegments/207 - Check maxMultipleCount against any remaining IPs included in a current double gesture.  CK: Unnecessary */
    pThis->multipleIPCount = 0;    /* Count number of IPs to advance. */
    if (maxMultipleCount <= 0)
        return(_FALSE);

    /* Prevent array access out of bounds in the first loop up to maxMultipleCount. */
    if (maxMultipleCount >= 12)
         maxMultipleCount = 12 - 1;

    IPOffsetLimit = IPLimit - pThis->ipIndex;
    if (IPOffsetLimit > 10)     /* Prevent ipOffset from overflowing array bounds */
        IPOffsetLimit = 10;

    doubleIPIndex = pThis->ipData->m_DoubleIPIndex;    /* Make sure maxMultipleCount is at least as big as number of IPs remaining in current Double IP (if Double IP detected) */
    doubleIPCount = 0;

    /* Check for matches with key1, key2 and key3 within multiple IP range */
    ipNext = pThis->ipData;        /* Initialize for case when pThis->forward == _FALSE */
    if (findMatchKey2)
    {
        for (ipOffset = 1; ipOffset <= maxMultipleCount; ipOffset++)
        {
            checkIPIndex = pThis->ipIndex + ipOffset;
            if (!pThis->forward)
                ipSeg1 = ipNext;
            ipNext = pThis->m_aIPTable[checkIPIndex];
            /* If we are in a double IP, and all IPs are within the double gesture, we can just call it good */
            if (doubleIPIndex && (doubleIPIndex == ipNext->m_DoubleIPIndex))
            {
                doubleIPCount++;
                /*DebugAssert(doubleIPCount == ipOffset); */
                if (doubleIPCount < ipOffset)       /* Ignore Double IP if not all IPs are included */
                {
                    doubleIPIndex = doubleIPCount = 0;
                }
            }
            isPathDivision = (ET9BOOL)(ipNext->m_IPType == PathDivision);
            bestMatch[ipOffset] = 0;
            if (pThis->forward)
            {
                ipSeg1 = ipNext;
                /* Occasionally have a multiple-IP sequence that is only found to be valid in one direction (forward or backward) */
                /* If sequence ceases to be valid in the current direction, re-set the maxMultipleCount limit */
                /*DebugAssert((ipOffset == maxMultipleCount) || (ipNext->m_ForwardMultipleCount > 0)); */
                if ((ipNext->m_ForwardMultipleCount == 0) && (ipOffset < maxMultipleCount))
                    maxMultipleCount = ipOffset;
            }
            else
            {
                /*DebugAssert((ipOffset == maxMultipleCount) || (ipNext->m_BackwardMultipleCount > 0)); */
                if ((ipNext->m_BackwardMultipleCount == 0) && (ipOffset < maxMultipleCount))
                    maxMultipleCount = ipOffset;
            }
            if (!isPathDivision)
            {
                key1IPScore[ipOffset] = _SWCSearchDB_GetIPWDistance(pThis, ipNext, pThis->key1);
                key2IPScore[ipOffset] = _SWCSearchDB_GetIPWDistance(pThis, ipNext, pThis->key2);
                if (key2IPScore[ipOffset])
                {
                    key2LastDuringIPMatch = ipOffset;
                    if (!key2DuringIPMatch)
                    {
                        key2DuringIPMatch = ipOffset;
                        key2DuringIPMatchCount = 1;
                    }
                    else if (ipOffset == (key2DuringIPMatch + key2DuringIPMatchCount))
                        key2DuringIPMatchCount++;
                    if (key1IPScore[ipOffset] && (key1IPScore[ipOffset] <= key2IPScore[ipOffset]))      /* Use <= to preference key1 matching */
                        bestMatch[ipOffset] = 1;
                    else
                        bestMatch[ipOffset] = 2;
                }
                else if (key1IPScore[ipOffset])
                    bestMatch[ipOffset] = 1;
                if (findMatchKey3)
                {
                    key3IPScore[ipOffset] = _SWCSearchDB_GetIPWDistance(pThis, ipNext, pThis->key3);
                    if (key3IPScore[ipOffset])
                    {
                        key3LastDuringIPMatch = ipOffset;
                        if (!key3DuringIPMatch)
                        {
                            key3DuringIPMatch = ipOffset;
                            key3DuringIPMatchCount = 1;
                        }
                        else if (ipOffset == (key3DuringIPMatch + key3DuringIPMatchCount))
                            key3DuringIPMatchCount++;
                        if ((bestMatch[ipOffset] == 1) && (key3IPScore[ipOffset] < key1IPScore[ipOffset]))
                            bestMatch[ipOffset] = 3;
                        else if ((bestMatch[ipOffset] == 2) && (key3IPScore[ipOffset] < key2IPScore[ipOffset]))
                            bestMatch[ipOffset] = 3;
                        else if (bestMatch[ipOffset] == 0)
                            bestMatch[ipOffset] = 3;
                    }
                }
            }
            key2SegScore[ipOffset] = _SWCSearchDB_GetSegmentWDistance(pThis, ipSeg1, pThis->key2, fixedLimit);
            if (key2SegScore[ipOffset])
            {
                key2LastDuringSegMatch = ipOffset;
                if (!key2DuringSegMatch)
                    key2DuringSegMatch = ipOffset;
            }
            if (findMatchKey3)
            {
                key3SegScore[ipOffset] = _SWCSearchDB_GetSegmentWDistance(pThis, ipSeg1, pThis->key3, fixedLimit);
                if (key3SegScore[ipOffset])
                {
                    key3LastDuringSegMatch = ipOffset;
                    if (!key3DuringSegMatch)
                        key3DuringSegMatch = ipOffset;
                }
            }
        }
    }
    /* If current double key matches multiple sequence of IPs from a single DoubleLetter gesture, call it good */
    /*   unless all remaining IPs are consumed */
    if ((doubleIPCount > 0) && ((pThis->ipIndex + doubleIPCount) < IPLimit) && (_SWCSearchDB_SetKeyMultipleIPs(pThis, pThis->key1, pThis->ipIndex, doubleIPCount, 0) > 0))
    {
        pThis->multipleIPCount = doubleIPCount;
        return(_TRUE);
    }
    if (findMatchKey2)
    {
        for (ipOffset = maxMultipleCount + 1; ipOffset <= IPOffsetLimit; ipOffset++)
        {
            checkIPIndex = pThis->ipIndex + ipOffset;
            if (!pThis->forward)
                ipSeg1 = ipNext;
            ipNext = pThis->m_aIPTable[checkIPIndex];
            isPathDivision = (ET9BOOL)(ipNext->m_IPType == PathDivision);
            wasMultiple = isMultiple;
            if (!isPathDivision)
            {
                if (pThis->forward)
                {
                    ipSeg1 = ipNext;
                    isMultiple = (ET9BOOL)(ipNext->m_ForwardMultipleCount > 0);
                }
                else
                    isMultiple = (ET9BOOL)(ipNext->m_BackwardMultipleCount > 0);
                key1IPScore[ipOffset] = _SWCSearchDB_GetIPWDistance(pThis, ipNext, pThis->key1);
                key2IPScore[ipOffset] = _SWCSearchDB_GetIPWDistance(pThis, ipNext, pThis->key2);
                if (key2IPScore[ipOffset])
                {
                    if (!key2FollowIPMatch)
                        key2FollowIPMatch = ipOffset;
                    if (isMultiple && !key2FollowIPMatchMultiple)
                    {
                        key2FollowIPMatchMultiple = ipOffset;
                        key2FollowIPMatchCount = 1;
                    }
                    else if ((isMultiple || wasMultiple) && (ipOffset == (key2FollowIPMatchMultiple + key2FollowIPMatchCount)))
                        key2FollowIPMatchCount++;
                }
                if (findMatchKey3)
                {
                    key3IPScore[ipOffset] = _SWCSearchDB_GetIPWDistance(pThis, ipNext, pThis->key3);
                    if (key3IPScore[ipOffset])
                    {
                        key3LastFollowIPMatch = ipOffset;
                        if (!key3FollowIPMatch)
                            key3FollowIPMatch = ipOffset;
                        if (isMultiple && !key3FollowIPMatchMultiple)
                        {
                            key3FollowIPMatchMultiple = ipOffset;
                            key3FollowIPMatchCount = 1;
                        }
                        else if ((isMultiple || wasMultiple) && (ipOffset == (key3FollowIPMatchMultiple + key3FollowIPMatchCount)))
                            key3FollowIPMatchCount++;
                    }
                }
            }
            key2SegScore[ipOffset] = _SWCSearchDB_GetSegmentWDistance(pThis, ipSeg1, pThis->key2, fixedLimit);
            if (!key2FollowSegMatch && key2SegScore[ipOffset])
                key2FollowSegMatch = ipOffset;
            if (findMatchKey3)
            {
                key3SegScore[ipOffset] = _SWCSearchDB_GetSegmentWDistance(pThis, ipSeg1, pThis->key3, fixedLimit);
                if (key3SegScore[ipOffset])
                {
                    key3LastFollowSegMatch = ipOffset;
                    if (!key3FollowSegMatch)
                        key3FollowSegMatch = ipOffset;
                }
            }
        }
    }
    if (findMatchKey2)
    {
        /* If we have a following double key, there are no more IPs after the current multiple sequence, and the key matches */
        /*   within the sequence, then the IPs must be allocated between both */
        key2MustShareIPs = (ET9BOOL)(pThis->key2IsDoubleKey && multipleIPsHitLimit && (key2DuringIPMatch > 0));
        key3MustShareIPs = (ET9BOOL)(findMatchKey3 && pThis->key3IsDoubleKey && multipleIPsHitLimit && (key3DuringIPMatch > 0));
        if (!multipleIPsHitLimit)       /* If we enter, then key2MustShareIPs and key3MustShareIPs have been set _FALSE */
        {
            if (pThis->key2IsDoubleKey)
            {
                if (key2DuringIPMatch > 0)                 /* Only need to share if there are possible matches */
                {
                    if (!key2FollowIPMatch)                                 /* No matches following multiple-IP sequence; must share available matches */
                        key2MustShareIPs = _TRUE;
                    else if (key2FollowIPMatchCount >= 2)                   /* No sharing needed if there is a following multiple-IP sequence of length 2 or greater */
                        key2MustShareIPs = _FALSE;
                    else if (maxMultipleCount >= 3)                         /* Multiple IP sequence is long enough to accommodate two successive multiple matches of length 2 or greater */
                        key2MustShareIPs = (ET9BOOL)(key2DuringIPMatchCount >= 2);       /* Force sharing if length 2 sequence available for key2 */
                    else if (findMatchKey3)                                 /* Only 2 or 3 Ips in sequence.  Force sharing only if needed to accomodate key3 */
                    {                                                       /* Multiple IP sequence is NOT long enough to accommodate two successive multiple matches with 2 IPs each */
                        /* If we have an available upcoming match for key3 */
                        if ((key3LastFollowIPMatch > key2FollowIPMatch) || (key3LastFollowSegMatch > key2FollowIPMatch))
                            key2MustShareIPs = _FALSE;
                        /* If no following match for key3... */
                        else if (!key3FollowIPMatch && !key3FollowSegMatch)
                        {
                            if (key3DuringIPMatch || key3DuringSegMatch)
                                key2MustShareIPs = key3MustShareIPs = _TRUE;
                            else
                                key2MustShareIPs = key3MustShareIPs = _FALSE;
                        }
                    }
                }
                if (findMatchKey3 && pThis->key3IsDoubleKey && key2MustShareIPs)
                {
                    if (key3DuringIPMatch > 0)                 /* Only need to share if there are possible matches */
                    {
                        if (!key3FollowIPMatch)                                 /* No matches following multiple-IP sequence; must share available matches */
                            key3MustShareIPs = _TRUE;
                        else if (key3FollowIPMatchCount >= 2)                   /* No sharing needed if there is a following multiple-IP sequence of length 2 or greater */
                            key3MustShareIPs = _FALSE;
                        else if (maxMultipleCount >= 5)                         /* Multiple IP sequence is long enough to accommodate three successive multiple matches of length 2 or greater */
                            key3MustShareIPs = (ET9BOOL)(key3DuringIPMatchCount >= 2);       /* Force sharing if length 2 sequence available for key2 */
                    }
                }
            }
            else        /* See if we need to find a matching location for (non-double) key2 */
            {
                if (findMatchKey3 && pThis->key3IsDoubleKey)               /* If key3 is double, confirm available upcoming double match first */
                {
                    if (key3DuringIPMatch > 0)                 /* Only need to share if there are possible matches */
                    {
                        if (!key3FollowIPMatch)                                 /* No matches following multiple-IP sequence; must share available matches */
                            key3MustShareIPs = _TRUE;
                        else if (key3FollowIPMatchCount >= 2)                   /* No sharing needed if there is a following multiple-IP sequence of length 2 or greater */
                            key3MustShareIPs = _FALSE;
                        else if (maxMultipleCount >= 3)                         /* Multiple IP sequence is long enough to accommodate two successive multiple matches of length 2 or greater */
                            key3MustShareIPs = (ET9BOOL)(key3DuringIPMatchCount >= 2);       /* Force sharing if length 2 sequence available for key2 */
                    }
                    if (key3MustShareIPs && (key2DuringIPMatch || key2DuringSegMatch))
                        key2MustShareIPs = _TRUE;
                }
                /*else if (!key2FollowIPMatch && !key2FollowSegMatch)      // No following match for key2 */
                /*{ */
                /*    if (key2DuringIPMatch || key2DuringSegMatch)    // key2 match available within current sequence */
                /*        key2MustShareIPs = _TRUE; */
                /*    else */
                /*        key2MustShareIPs = _FALSE;                   // No matches anywhere for key2 */
                /*    if (findMatchKey3) */
                /*        key3MustShareIPs = (!key3FollowIPMatch && !key3FollowSegMatch && (key3DuringIPMatch || key3DuringSegMatch)); */
                /*} */
                /*else if (findMatchKey3)     // Only share if can't otherwise match key2 prior to key3 */
                /*{       // key2 matched during sequence,             but key3 didn't,                           but key3 did match following the sequence... */
                /*    if ((key2DuringIPMatch || key2DuringSegMatch) && !key3DuringIPMatch && !key3DuringSegMatch && (key3FollowIPMatch || key3FollowSegMatch)) */
                /*    {   // Then key2 must share unless there is an in-order following match of key2 and key3 */
                /*        if ((key2FollowIPMatch && ((key3LastFollowIPMatch > key2FollowIPMatch) || (key3LastFollowSegMatch > key2FollowIPMatch))) || */
                /*            (key2FollowSegMatch && ((key3LastFollowIPMatch > key2FollowSegMatch) || (key3LastFollowSegMatch > key2FollowSegMatch)))) */
                /*            key2MustShareIPs = _FALSE; */
                /*        else */
                /*            key2MustShareIPs = _TRUE; */
                /*    } */
                /*} */
                else
                {   /* TODO(CAK): Confirm that this is a sufficient test. */
                    /* If there IS a following match for key2, OR if there is NOT a match during, then don't force sharing for key2 */
                    SBYTE2 key2FinalDuringMatchIndex = sw_max(key2LastDuringSegMatch, key2LastDuringIPMatch);        /* Set if location is determined for key2 or key3 below */
                    SBYTE2 key3FinalDuringMatchIndex = sw_max(key3LastDuringSegMatch, key3LastDuringIPMatch);        /* Set if location is determined for key2 or key3 below */
                    if ((key2FollowIPMatch || key2FollowSegMatch) || (!key2DuringIPMatch && !key2DuringSegMatch))
                        key2MustShareIPs = _FALSE;
                    else
                    {
                        /* Solve "loop" problem - check for match at end of long-enough sequence */
                        key2MustShareIPs = _TRUE;
                    }
                    /* Then similarly, but also in addition for key3, if key2 doesn't need to share, don't force a back-track for key3 */
                    /* Also, if no following match for needed key3, look for first match from end for key3 first */
                    if (!key2MustShareIPs || !findMatchKey3 || key3FollowIPMatch || key3FollowSegMatch || (!key3DuringIPMatch && !key3DuringSegMatch))
                        key3MustShareIPs = _FALSE;
                    else
                        key3MustShareIPs = _TRUE;
                    DebugAssert(pThis->multipleIPCount == 0);
                    if (key3MustShareIPs)           /* Means we must try to find match positions for both key3 and key2.  Find latest possible */
                    {
                        /* Don't ruin chance for valid double-key match - leave 1 (additional) IP for multiple IPs match */
                        /* For now, don't worry whether key2 and key3 matches are in order */
                        if ((key3FinalDuringMatchIndex > 1) && (key2FinalDuringMatchIndex > 1))
                        {
                            pThis->multipleIPCount = sw_min((key3FinalDuringMatchIndex - 1), (key2FinalDuringMatchIndex - 1));
                            DebugAssert(pThis->multipleIPCount >= 1);
                            key3MustShareIPs = _FALSE;
                        }
                    }
                    else if (key2MustShareIPs && (key2FinalDuringMatchIndex > 1))           /* Means we must try to find match positions for both key3 and key2.  Find latest possible */
                    {
                        pThis->multipleIPCount = key2FinalDuringMatchIndex - 1;
                        DebugAssert(pThis->multipleIPCount >= 1);
                        key2MustShareIPs = _FALSE;
                    }
                    if (pThis->multipleIPCount > 0)
                        maxMultipleCount = pThis->multipleIPCount;         /* Use all IPs except those required for key2 and key3 match */
                }
            }
        }
    }

    if (!key2MustShareIPs && !key3MustShareIPs)         /* Just grab all the IPs that match key1 */
    {
        /* Confirm that each included IP is valid */
        addAnother = _TRUE;
        pThis->multipleIPCount = 0;
        for (ipOffset = 1; (ipOffset <= maxMultipleCount) && addAnother; ipOffset++)
        {
            addAnother = (ET9BOOL)(_SWCSearchDB_SetKeyMultipleIPs(pThis, pThis->key1, pThis->ipIndex, ipOffset, 0) > 0);
            if (addAnother)
            {
                /* First confirm that we really want to consume the final IP that matches key2 in a multiple match for key1 */
                if ((ipOffset == key2LastDuringIPMatch) &&                      /* This is the final IP matching key2 (within the gesture) */
#if CAN_REQUIRE_DOUBLE_GESTURE
                    (!pThis->doubleGestureRequired || (ipOffset > 1)) &&               /* Either double gesture is not required, or we already have at least two IPs */
#endif
                    (_SWPoint_distance8(&Key2Loc, &pThis->m_aIPTable[pThis->ipIndex + ipOffset]->m_IPLocation) < pThis->keyMultipleIPsDistance) &&        /* key2 is closer to IP than key1 is to gesture center */
                    (_SWPoint_distance8(&Key1Loc, &pThis->m_aIPTable[pThis->ipIndex + ipOffset - 1]->m_IPLocation) < pThis->keyMultipleIPsDistance))      /* key1 is closer (or about as close) to previous IP than it is to gesture center */
                {
                    addAnother = _FALSE;
                }
                if (addAnother)
                    pThis->multipleIPCount = ipOffset;
            }
        }
        if (pThis->multipleIPCount <= 0)
        {
            return(_FALSE);
        }
        return(_TRUE);
    }

    /* May have bestMatch[] element set to a non-competing key.  Fix now if necessary. */
    for (ipOffset = 1; ipOffset <= maxMultipleCount; ipOffset++)
    {
        if (!key2MustShareIPs && (bestMatch[ipOffset] == 2))
        {
            if (key1IPScore[ipOffset] && key3IPScore[ipOffset])
            {
                if (key1IPScore[ipOffset] <= key3IPScore[ipOffset])
                    bestMatch[ipOffset] = 1;
                else
                    bestMatch[ipOffset] = 3;
            }
            else if (key1IPScore[ipOffset])
                bestMatch[ipOffset] = 1;
            else if (key3IPScore[ipOffset])
                bestMatch[ipOffset] = 3;
            else
                bestMatch[ipOffset] = 0;
        }
        if (!key3MustShareIPs && (bestMatch[ipOffset] == 3))
        {
            if (key1IPScore[ipOffset] && key2IPScore[ipOffset])
            {
                if (key1IPScore[ipOffset] <= key2IPScore[ipOffset])
                    bestMatch[ipOffset] = 1;
                else
                    bestMatch[ipOffset] = 2;
            }
            else if (key1IPScore[ipOffset])
                bestMatch[ipOffset] = 1;
            else if (key2IPScore[ipOffset])
                bestMatch[ipOffset] = 2;
            else
                bestMatch[ipOffset] = 0;
        }
    }
    /* See if we can carve out matches for key2 and/or key3 */
    ipNext = pThis->ipData;        /* Initialize for case when pThis->forward == _FALSE */
    for (ipOffset = 1; ipOffset <= maxMultipleCount; ipOffset++)
    {
        if (bestMatch[ipOffset] == 1)
        {
            if (!firstKey1BestMatch)
                firstKey1BestMatch = ipOffset;
            lastKey1BestMatch = ipOffset;
            if (lastBestMatch > 1)
                bestMatchesInSequence = _FALSE;
            lastBestMatch = 1;
        }
        else if (bestMatch[ipOffset] == 2)
        {
            if (!firstKey2BestMatch)
                firstKey2BestMatch = ipOffset;
            lastKey2BestMatch = ipOffset;
            if (lastBestMatch > 2)
                bestMatchesInSequence = _FALSE;
            lastBestMatch = 2;
        }
        else if (bestMatch[ipOffset] == 3)
        {
            if (!firstKey3BestMatch)
                firstKey3BestMatch = ipOffset;
            lastKey3BestMatch = ipOffset;
            if (lastBestMatch > 3)
                bestMatchesInSequence = _FALSE;
            lastBestMatch = 3;
        }
    }

    if (bestMatchesInSequence)
    {
        if (firstKey1BestMatch)
        {
            ET9BOOL matchesKey1 = _TRUE;
            for (ipOffset = firstKey1BestMatch; (ipOffset <= maxMultipleCount) && matchesKey1; ipOffset++)
            {
                matchesKey1 = (ET9BOOL)(bestMatch[ipOffset] == 1);
                if (matchesKey1)
                    finalKey1Match = ipOffset;
            }
            if (finalKey1Match && (_SWCSearchDB_SetKeyMultipleIPs(pThis, pThis->key1, pThis->ipIndex, finalKey1Match, 0) > 0))
            {
                pThis->multipleIPCount = finalKey1Match;
                return(_TRUE);
            }
        }
    }
    /* SavedCodeSegments/280 - CheckMultipleIPsMatchOld() check */
    return(_FALSE);
    /* SavedCodeSegments/252 - Mish-mash of new CheckMultipleIPsMatch() approach and CheckMultipleIPsMatchOld() - may use (as starting point) if additional testing is indicated */
}   /* _SWCSearchDB_CheckMultipleIPsMatch() */

/* Calculate location of combined point, and set keyMultipleIPs according to distance from combined point */
/* Return number of IPs matched by key, if >= minMatchCount, otherwise return 0 */
SBYTE2 ET9FARCALL _SWCSearchDB_SetKeyMultipleIPs(_SWCSearchDB *pThis, BYTE1 multKey, SBYTE2 startIndex, SBYTE2 multipleCount, SBYTE2 minMatchCount)
{
    SWCIPTableRow *ipNext, *ipLast;
    _SWPoint     KeyLoc;
    SBYTE2      mergeCount, matchCount;
    SBYTE2 i;

    if (minMatchCount == 0)         /* Reset minMatchCount if passed in as default value */
        minMatchCount = (multipleCount + 1);
    ipNext = pThis->m_aIPTable[startIndex];
    if (ipNext->m_DoubleIPIndex > 0)
    {
        if (pThis->forward)
        {
            pThis->matchKeyLocIndex = ipNext->gestureIn;
            pThis->matchKeyLocExitIndex = ipNext->gestureOut;
        }
        else
        {
            pThis->matchKeyLocIndex = ipNext->gestureOut;
            pThis->matchKeyLocExitIndex = ipNext->gestureIn;
        }
        pThis->matchKeyPos = ipNext->gestureLoc;
        matchCount = (multipleCount + 1);
    }
    else
    {
        if (multipleCount < 1)
            return(0);
        mergeCount = matchCount = 0;
        pThis->matchKeyPos.x = 0;
        pThis->matchKeyPos.y = 0;
        if (pThis->forward)
        {
            pThis->matchKeyLocIndex = ipNext->m_FixedIndexIn;
            pThis->matchKeyLocExitIndex = ipNext->m_FixedIndexOut;
        }
        else
        {
            pThis->matchKeyLocIndex = ipNext->m_FixedIndexOut;
            pThis->matchKeyLocExitIndex = ipNext->m_FixedIndexIn;
        }
        ipNext = (startIndex > 0) ? pThis->m_aIPTable[startIndex - 1] : NULL;
        for (i = 0; (i <= multipleCount); i++)
        {
            ipLast = ipNext;
            ipNext = pThis->m_aIPTable[startIndex + i];
            if (_SWCSearchDB_GetIPWDistance(pThis, ipNext, multKey))
            {   /* Add appropriate weighting to each included IP location */
                pThis->matchKeyPos.x = (SBYTE2)(pThis->matchKeyPos.x + ipNext->m_IPLocation.x * (SBYTE2)ipNext->m_MergeCount);
                pThis->matchKeyPos.y = (SBYTE2)(pThis->matchKeyPos.y + ipNext->m_IPLocation.y * (SBYTE2)ipNext->m_MergeCount);
                mergeCount = (SBYTE2)(mergeCount + (SBYTE2)ipNext->m_MergeCount); /* Count number of coordinate values summed (including weighting) */
                matchCount++;
            }
            else
            {
                if (matchCount < minMatchCount)
                {
                    if (matchCount > 0)     /* Calculate match location if at least one matching IP found */
                    {
                        if (ipLast != NULL)
                        {
                            if (pThis->forward)
                                pThis->matchKeyLocExitIndex = ipLast->m_FixedIndexOut;
                            else
                                pThis->matchKeyLocExitIndex = ipLast->m_FixedIndexIn;
                        }
                        if (mergeCount >= 1)
                        {
                            pThis->matchKeyPos.x = (pThis->matchKeyPos.x + pThis->multipleIPCount) / mergeCount;
                            pThis->matchKeyPos.y = (pThis->matchKeyPos.y + pThis->multipleIPCount) / mergeCount;
                        }
                    }
                    return(0);
                }
                else
                    break;
            }
        }
        if (ipNext != NULL)
        {
            if (pThis->forward)
                pThis->matchKeyLocExitIndex = ipNext->m_FixedIndexOut;
            else
                pThis->matchKeyLocExitIndex = ipNext->m_FixedIndexIn;
        }
        if (mergeCount >= 1)
        {
            pThis->matchKeyPos.x = (pThis->matchKeyPos.x + pThis->multipleIPCount) / mergeCount;
            pThis->matchKeyPos.y = (pThis->matchKeyPos.y + pThis->multipleIPCount) / mergeCount;
        }
    }
    pThis->matchKeyPosIndex = (pThis->matchKeyLocIndex + pThis->matchKeyLocExitIndex) / 2;
    pThis->matchKeyLoc = _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->matchKeyLocIndex);

    SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, multKey, &KeyLoc);     /* Get location of key */
    pThis->keyMultipleIPsDistance = _SWPoint_distance8(&KeyLoc, &pThis->matchKeyPos);     /* distance8() returns min value of 1 */
#if USE_DISTANCE2Y8_IP
    pThis->keyMultipleIPsWDistance = _SWPoint_distance2y8(&pThis->m_backend->sScreenGeometry, &KeyLoc, &pThis->matchKeyPos);
#else
    pThis->keyMultipleIPsWDistance = pThis->keyMultipleIPsDistance;
#endif
    if (pThis->keyMultipleIPsWDistance < MIN_IP_WDISTANCE8)
        pThis->keyMultipleIPsWDistance = (pThis->keyMultipleIPsWDistance + MIN_IP_WDISTANCE8) / 2;
    pThis->keyMultipleIPs = (BYTE2)(long)(pThis->keyMultipleIPsWDistance * MultipleIPsWeight);
    return(matchCount);
}
/* Apply test to determine whether key1 should wait until after Exit IP to match Seg2 */
ET9BOOL ET9FARCALL _SWCSearchDB_MatchKey1AfterExit(_SWCSearchDB *pThis)
{
    ET9BOOL    waitMatch = (ET9BOOL)(pThis->forward && (pThis->ipData->m_IPType == Exit) && (pThis->key1Seg2 || pThis->key1IP2) &&  /* There IS a valid key1 match following the exit, and either: */
             ((pThis->key1Seg2 && pThis->key2IP2 && (!pThis->IP2isPenUp || (pThis->keysRemaining == 2))) ||                 /* (1) key2 matches (an available) IP2 following a Seg2 match for key1, OR */
              (pThis->key1Seg2 && pThis->key2Seg2 && (pThis->key1Seg2PosIndex <= pThis->key2Seg2PosIndex) &&                /* (2) key2 matches Seg2 following a Seg2 match for key1, AND */
                (pThis->m_SearchFirstLetterShiftGesture || ((3 * pThis->key1Seg2) < (2 * pThis->key1Seg1)))) ||             /*     this is a firstLetterShiftGesture or Seg2 match is noticeably better than Seg1 match, OR */
              ((!pThis->key2Seg1 || (pThis->key1Seg1PosIndex > pThis->key2Seg1PosIndex)) && !pThis->key2Seg2 && !pThis->key2IP2) || /* (3) key2 doesn't match prior to the exit (or doesn't match in order), and key2 doesn't match anywhere on the following Seg2 or IP2 */
              (pThis->key1IP2 && (pThis->key2Seg3 || pThis->key2IP3)) ||                                                    /* (4) key2 matches Seg3 or IP3 following a IP2 match for key1, OR */
              (pThis->key1IP2 && pThis->key1IsDoubleKey && (pThis->ipData2->m_ForwardMultipleCount > 0))));                 /* (5) key1 is Double key that matches multiple-count IP2 */
    return(waitMatch);
}

/* Apply test to determine whether key2 should wait until after following Exit IP to match Seg3 or IP3 */
ET9BOOL ET9FARCALL _SWCSearchDB_MatchKey2AfterExit(_SWCSearchDB *pThis)
{
    ET9BOOL    waitMatch = (ET9BOOL)(pThis->forward && (pThis->ipData2 != NULL) && (pThis->ipData2->m_IPType == Exit) && (pThis->key2Seg3 || pThis->key2IP3));       /* There IS a valid key2 match following the exit, and either: */
    return(waitMatch);
}


/* Apply test to determine whether key1 can wait until after PathDivision IP to match Seg2 */
ET9BOOL ET9FARCALL _SWCSearchDB_MatchKey1AfterPathDivision(_SWCSearchDB *pThis)
{
    /*ET9BOOL    waitMatch = (ET9BOOL)(pThis->IP1isPathDivision && (pThis->key1Seg2 || pThis->key1IP2)); */
    /*ET9BOOL    waitMatch = (ET9BOOL)(pThis->IP1isArtificial && (pThis->key1IP2 || (pThis->key1Seg2 && (!pThis->key1Seg1 || (pThis->key1Seg2 < pThis->key1Seg1))))); */
    ET9BOOL    waitMatch = (ET9BOOL)(pThis->IP1isArtificial && (pThis->key1IP2 || pThis->key1Seg2 || (pThis->IP2isArtificial && (pThis->key1IP3 || pThis->key1Seg3))));
    return(waitMatch);
}


/* Apply complex test to determine whether key1 should match Seg1 rather than possible IP1 match */
ET9BOOL ET9FARCALL _SWCSearchDB_MatchKey1ToSeg1(_SWCSearchDB *pThis, SBYTE2 *matchKeyVal)
{
    SBYTE2 multipleCount1;
    *matchKeyVal = THIS_SEGMENT_MATCH;       /* Init to default return value */
    if (pThis->key2 == SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))     /* If there is a possible IP match, match it now if there is no following key */
    {
        if (pThis->forward && (pThis->ipData->m_IPType == SoftUp) && (pThis->ipData->m_fIPWeight == ExitUpWeight) && (pThis->key1Seg1 < pThis->key1IP1))
            return(_TRUE);
        return(_FALSE);
    }
    multipleCount1 = (pThis->forward) ? pThis->ipData->m_ForwardMultipleCount : pThis->ipData->m_BackwardMultipleCount;
    if (pThis->key2IP1)
    {
        ET9BOOL key2MatchesAfterExit = _SWCSearchDB_MatchKey2AfterExit(pThis);  /* Check whether following IP is an exit IP, and key2 can/should match following exit */
        /* If key2 is an unmatched doubleKey that matches both following IPs (presumably a Multiple IPs match) */
        /* and average distance of key2 is less than current distance of key1 */
        /* and segment match score of key1 is less than half the IP match score of key1 */
        if (pThis->key2IP2 && pThis->key2IsDoubleKey)
        {
            SBYTE2 multipleCount2 = (pThis->forward) ? pThis->ipData2->m_ForwardMultipleCount : pThis->ipData2->m_BackwardMultipleCount;
            if (multipleCount1 > 0)
            {
                /* If double key2 can still match even if current IP is consumed by key1, check for key2 reasonable match with current IP */
                /* to determine which is likely best match for IP1 */
                /* Penalty would be invoked for matching key to a circle gesture Double IP, so check if IP1 is part of a circle gesture. */
                /* Otherwise, try to identify optimal matching */
                ET9BOOL DoubleIPisCircleGesture = _FALSE;
                if (pThis->ipData->m_DoubleIPIndex > 0)
                    DoubleIPisCircleGesture = pThis->m_aIPTable2[pThis->ipData->m_DoubleIPIndex - 1]->signChangesOK;
                if (!DoubleIPisCircleGesture)
                {
                    ET9BOOL matchKey1toIP = _FALSE;
                    if (multipleCount2 > 0)     /* Examine multiple match starting with following IP */
                    {
                        BYTE2 key1toIPdistance = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);
                        BYTE2 key1toSegDistance = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->ipData, pThis->key1);
                        matchKey1toIP = (ET9BOOL)(key1toIPdistance <= key1toSegDistance);
                    }
                    if ((!matchKey1toIP && (pThis->key1Seg1 < pThis->key1IP1) && (pThis->key2IP1 < pThis->key1IP1)) || (multipleCount2 == 0))
                    {

                        if (_SWCSearchDB_SetKeyMultipleIPs(pThis, pThis->key2, pThis->ipIndex, multipleCount1, 0))       /* Make sure multiple match is valid */
                        {
                            float   dummySlopeDifFactor, dummyLengthFactor;
                            if (_SWCSearchDB_calcSlopeDif(pThis, pThis->key1, pThis->key2, SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm), _FALSE, _FALSE, _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->key1Seg1PosIndex), pThis->matchKeyPos,
                                             pThis->key1Seg1PosIndex, pThis->matchKeyPosIndex, &dummySlopeDifFactor, &dummyLengthFactor, 0, 0, 0, 0, _FALSE))
                                return(_TRUE);
                        }
#if DEBUG_LOG_MATCH_TRACE
                        if (debugThis)
                        {
                            Log(SWLogger_DEBUG, TEXT(" ...Forcing rejection of THIS_SEGMENT_MATCH 1/2 for key %d after calcSlopeDif() call.\n\r"), pThis->keyIndex);
                        }
#endif
                    }
                    return(_FALSE);
                }
                else        /* */
                {
                    return(_TRUE);       /* Just match to segment if current IP is part of a matched circle gesture for following double-letter */
                }
            }
        }
        /* Check whether current IP1 may be the result of an error and should be skipped in favor of next segment or IP */
        /* See if IP2 requires key1 */
        {
            ET9BOOL IP2MatchRequiresKey1 = (ET9BOOL)(pThis->key1IP2 && !pThis->key2IP2 && !pThis->key3IP2 && (!pThis->key4IP2 || !pThis->key3Seg2) &&     /* key1 is only upcoming match for IP2 */
                                           (pThis->key1IP2 < pThis->key1IP1) &&                  /* key1 is better match for IP2 than IP1 */
                                           (pThis->key2Seg3 || pThis->key2IP3) &&                /* key2 and key 3 have later upcoming matches */
                                           (pThis->key3Seg3 || pThis->key3IP3));
            if (IP2MatchRequiresKey1)
            {
                *matchKeyVal = NO_PATTERN_MATCH;       /* Force skipping of current IP */
                return(_TRUE);
            }
        }
        {
            BYTE2 key2Next = _SWCSearchDB_minNonZero(pThis->key2IP2, pThis->key2Seg2);
            float   slopeDifFactorKey1MatchesIP, slopeDifFactorKey2MatchesIP, dummyLengthFactor;
            ET9BOOL Key2MatchesIP1 = _SWCSearchDB_calcSlopeDif(pThis, pThis->key1, pThis->key2, SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm), _FALSE, _FALSE, _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->key1Seg1PosIndex), pThis->ipData->m_IPLocation,
                                    pThis->key1Seg1PosIndex, pThis->ipData->m_IPPosIndex, &slopeDifFactorKey2MatchesIP, &dummyLengthFactor, 0, 0, 0, 0, _FALSE);
            ET9BOOL key2isBetterIP1Match = (ET9BOOL)(Key2MatchesIP1 && (!key2Next || ((pThis->key1Seg1 + pThis->key2IP1) < (pThis->key1IP1 + key2Next))));
            /* If key2 does not match next IP or key3 or key4 is a better match than key2, */
            /* and key2 yields a better score, then match key1 to current segment */
            ET9BOOL IP2MatchDoesNotRequireKey2 = (ET9BOOL)(!pThis->key2IP2 || (pThis->key3IP2 && (pThis->key3IP2 < pThis->key2IP2)) || (pThis->key4IP2 && (pThis->key4IP2 < pThis->key2IP2)));
            if (key2isBetterIP1Match && IP2MatchDoesNotRequireKey2)
                return(_TRUE);
            /* If key2 cannot match next IP or segment, and even if available, any following segment match is a worse match, then match key1 to current segment */
            if (!key2Next && (!pThis->key2Seg3 || ((pThis->key1IP1 + pThis->key2Seg3) > (pThis->key1Seg1 + pThis->key2IP1))))
                return(_TRUE);
            /* If key2 also matches the following segment, and is not required for an IP2 match, */
            /* and if key3 is not a good match for IP1 (following in-sequence segment matches for key1 and key2), */
            /* then evaluate whather key1 or key2 should match IP1 */
            if (pThis->key2Seg2 &&                         /* key2 also matches following segment */
                IP2MatchDoesNotRequireKey2 &&       /* key2 not needed for IP2 match */
                (!pThis->key2Seg1 || !pThis->key3IP1 || !_SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex) || ((pThis->key3IP1 > pThis->key1IP1) && (pThis->key3IP1 > pThis->key2IP1)))  /* key3 not a good choice for IP1 */
                )
            {
                ET9BOOL Key1MatchesIP1;
                pThis->nextKeyCheckAlternateMatches = _TRUE;        /* Allow alternate slope dif calculation since either key could match segment or IP */

                Key1MatchesIP1 = _SWCSearchDB_calcSlopeDif(pThis, pThis->key1, pThis->key2, SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm), _FALSE, _FALSE, pThis->ipData->m_IPLocation, _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->key2Seg2PosIndex),
                                        pThis->ipData->m_IPPosIndex, pThis->key2Seg2PosIndex, &slopeDifFactorKey1MatchesIP, &dummyLengthFactor, 0, 0, 0, 0, _FALSE);
                if (!Key1MatchesIP1 && key2MatchesAfterExit)        /* Check for valid matches if key2 matches following an exit */
                {
                    if (pThis->key2IP3)
                    {
                        Key1MatchesIP1 = _SWCSearchDB_calcSlopeDif(pThis, pThis->key1, pThis->key2, SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm), _FALSE, _FALSE, pThis->ipData->m_IPLocation, pThis->ipData3->m_IPLocation,
                                        pThis->ipData->m_IPPosIndex, pThis->ipData3->m_IPPosIndex, &slopeDifFactorKey1MatchesIP, &dummyLengthFactor, 0, 0, 0, 0, _FALSE);
                    }
                    if (!Key1MatchesIP1 && pThis->key2Seg3)
                    {
                        Key1MatchesIP1 = _SWCSearchDB_calcSlopeDif(pThis, pThis->key1, pThis->key2, SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm), _FALSE, _FALSE, pThis->ipData->m_IPLocation, _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->key2Seg3PosIndex),
                                        pThis->ipData->m_IPPosIndex, pThis->key2Seg3PosIndex, &slopeDifFactorKey1MatchesIP, &dummyLengthFactor, 0, 0, 0, 0, _FALSE);
                    }
                }
                if (Key1MatchesIP1 && Key2MatchesIP1)
                {
                    /* Take segment scores into account if no in-sequence IP matching coming up for key2 */
                    if (!pThis->key2IP2 || (pThis->key3IP2 && !pThis->key3IP3 && !pThis->key3Seg2))
                    {
                        return (key2isBetterIP1Match);    /* Go with whichever produces a better score */
                    }
                    else
                    {
                        return (ET9BOOL)(pThis->key1IP1 > pThis->key2IP1);  /* Go with whichever has the better score for the current IP */
                    }
                }
                else
                    return (ET9BOOL)(pThis->requiredIP && (Key2MatchesIP1 || (!Key1MatchesIP1 && !key2MatchesAfterExit)));
            }

            /* OR if following IP is SoftUp and next key is final key */
            if (pThis->IP1canBePenUp && (pThis->keysRemaining == 2) && (!pThis->key2IP2 || ((pThis->key1Seg1 + pThis->key2IP1) < (pThis->key1IP1 + pThis->key2IP2))))
            {
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    Log(SWLogger_DEBUG, TEXT(" ...Forcing THIS_SEGMENT_MATCH 3 for key %d due to IP1canBePenUp.\n\r"), pThis->keyIndex);
                }
#endif
                return(_TRUE);
            }
            /* OR if we are scoring a suffix, match keys in order at earliest possible time */
            if (!pThis->forward)
            {
                if (pThis->keysRemaining == 1)
                    return(_TRUE);
                if (key2isBetterIP1Match)
                    return(_TRUE);
            }
        }
        /* OR if key3 matches next IP, and match with key2 */
        /*   is better than key1 match or key2 match with next IP (handled above with key2isBetterIP1Match test) */
    }
    /* OR if key2 matches current segment */
    if (pThis->key2Seg1)
    {
        if (_SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex))    /* If key2 matches current segment in proper order */
        {
            /* AND if we are scoring a suffix, match keys in order at earliest possible time */
            if (!pThis->forward && ((pThis->keysRemaining == 2) || (!pThis->key2IP1 || pThis->key3IP1 || (pThis->key3Seg1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key2Seg1PosIndex, pThis->key3Seg1PosIndex)))))
                return(_TRUE);
            /* AND if neither key2 nor key3 can match IP2 */
            if (!pThis->key2IP2 && (!pThis->key3IP2 || !pThis->key2Seg2))
            {
                /* AND if key3 matches current IP and neither key2 nor key3 can match IP2 */
                if (pThis->key3IP1)
                    return(_TRUE);
                /* OR if key3 and key2 match current segment in proper order */
                if (pThis->key3Seg1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key2Seg1PosIndex, pThis->key3Seg1PosIndex))
                    return(_TRUE);           /* ??? Require search for "key4" that matches IP1 ??? */
            }
            /* OR If key3 is an unmatched doubleKey that matches both following IPs (presumably a Multiple IPs match) */
            /* and segment distance of key1 is less than its IP distances */
            else if (pThis->key3IP1 && pThis->key3IP2 && pThis->key3IsDoubleKey && multipleCount1)
            {
                if (pThis->key1Seg1 < pThis->key1IP1)
                    return(_TRUE);
            }
            else if (pThis->key4IP1)
            {
                if (pThis->key3Seg1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key2Seg1PosIndex, pThis->key3Seg1PosIndex))
                    return(_TRUE);           /* We identified "key4" that matches IP1 */
            }
        }
        else
        {
            if (pThis->key2Seg1 < pThis->key1Seg1)       /* If key2 is a better segment match, see if key1 should be omitted */
            {               /* See if this appears to be the last chance to match key2 */
                if (!pThis->key2IP1 && !pThis->key2IP2 && !pThis->key2Seg2 && !pThis->key2Seg3 && !pThis->key2IP3)
                {
                    *matchKeyVal = OMIT_CURRENT_KEY;     /* Flag omission of key */
                    return(_TRUE);
                }
            }
            /* See if other evidence indicates key1 should be omitted */
            /* If key2 segment match follows preceding key match, AND.. */
            if (_SWCSearchDB_MatchKey2ToSeg1(pThis))
            {
                *matchKeyVal = OMIT_CURRENT_KEY;     /* Flag omission of key */
                return(_TRUE);
            }
        }
    }
        /* OR If we are already at the PenUp IP */
        /* OR If the next IP is the PenUp IP, and key2 MUST match the current IP */
    if (pThis->IP1isPenUp || (pThis->IP2isPenUp && pThis->key2IP1 && !pThis->key2Seg2 && pThis->key3IP2))
        return(_TRUE);
    /* If key3 is significantly better match for IP1, see if key2 and key3 might need to swap to get better score on IP1 (and key3) */
    if (pThis->requiredIP && pThis->key3IP1 && ((2 * pThis->key3IP1) < pThis->key1IP1) && (pThis->key2IP2 || pThis->key2Seg2) && !pThis->key3IP2)
    {
        if (pThis->key2Seg2 && (pThis->key3IP2 || (pThis->key3Seg2 && _SWCSearchDB_PointsInSequence(pThis, pThis->key2Seg2PosIndex, pThis->key3Seg2PosIndex))))
            return(_FALSE);
        if (pThis->key2IP2 && (pThis->key3Seg3 || pThis->key3IP3))
            return(_FALSE);
        return(_TRUE);
    }
    return(_FALSE);
}

/* Apply complex test to determine whether key2 should match Seg1 rather than possible IP1 match for key1 */
ET9BOOL ET9FARCALL _SWCSearchDB_MatchKey2ToSeg1(_SWCSearchDB *pThis)
{
    if (pThis->isMGDataBase || pThis->key1IP1 || pThis->key2IP1 || pThis->key2IP2)   /* Don't pass up obvious upcoming match opportunities */
        return(_FALSE);
    /* See if other evidence indicates key1 should be omitted */
    /* If key2 segment match follows preceding key match, AND.. */
    if (_SWCSearchDB_PointsInSequence(pThis, pThis->lastMatchKeyPosIndex, pThis->key2Seg1PosIndex) &&
        /* key2 AND key3 have a significantly better match to the segment than key1 matches IP1, or if we also have a match for key4 with IP1 or Seg1 */
        ((pThis->key3Seg1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key2Seg1PosIndex, pThis->key3Seg1PosIndex) && (pThis->IP1isPathDivision || (!pThis->key1IP1 && !pThis->key2IP1)) &&
         (pThis->IP1isPenUp ||
          (pThis->key4Seg1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key3Seg1PosIndex, pThis->key4Seg1PosIndex) && (!pThis->key1IP1 || ((pThis->key4Seg1 + pThis->key2Seg1 + pThis->key3Seg1) < ((4 * pThis->key1IP1)/3)))) ||
          (pThis->key4IP1 && (!pThis->key1IP1 || ((pThis->key4IP1 + pThis->key2Seg1 + pThis->key3Seg1) < ((4 * pThis->key1IP1)/3)))) ||
          ((pThis->key2Seg1 + pThis->key3Seg1) < (pThis->key1IP1/2)) ||
          ((pThis->key4Seg2 && (!pThis->key4Seg1 || (pThis->key4Seg2 < pThis->key4Seg1)) && !pThis->key1IP1) || (pThis->key4IP2 && !pThis->key2IP2 && !pThis->key3IP2))
         )
        ) ||
        /* OR, if key3 has a significantly better match to IP1 or this is already the PenUp, or key4 matches Seg2 or IP2 and key2 matches Seg1 relatively better */
        (pThis->key3IP1 && (pThis->key3IP1 <= pThis->key1IP1) && (pThis->IP1isPenUp ||
                                             ((pThis->key4Seg2 || pThis->key4IP2) && ((_SWCSearchDB_minNonZero(pThis->key4Seg2, pThis->key4IP2) + pThis->key2Seg1 + pThis->key3IP1) < ((pThis->key1IP1 * 5) / 3))) ||
                                             ((pThis->key2Seg1 + pThis->key3IP1) < (pThis->key1IP1/2)))))
       )
    {
        return(_TRUE);
    }
    return(_FALSE);
}

ET9BOOL ET9FARCALL _SWCSearchDB_SwapNextKeyOK(_SWCSearchDB *pThis, SBYTE2 *chkMatchKey)
{
    ET9BOOL    doubleKeyMatchesMultiple = (ET9BOOL)((pThis->key1IsDoubleKey || pThis->key2IsDoubleKey) &&
                                       ((pThis->forward && (pThis->ipData->m_ForwardMultipleCount > 0)) || (!pThis->forward && (pThis->ipData->m_BackwardMultipleCount > 0))));
    *chkMatchKey = pThis->matchKey;     /* Init to current value in case no change */
    if (pThis->key2IP1)    /* If key2 matches current IP return flag signaling possible match */
    {
        /* Check whether key1 matching should be delayed in order to match both key1 and key2 in proper sequence, without */
        /*   forcing following key to miss an in-order matching opportunity */
        if (!pThis->key1Seg1 && pThis->key1IP2 && !doubleKeyMatchesMultiple &&
             pThis->key2IP3 &&
             ((3 * pThis->key2IP3) < (5 * pThis->key2IP1)) &&
             (!pThis->key3IP3 || ((pThis->key2IP3 < pThis->key3IP3) && (pThis->keysRemaining > 3)))
            )
        {
#if DEBUG_LOG_MATCH_TRACE
            if (debugThis)
            {
                Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 3 for key %d.\n\r"), pThis->keyIndex);
            }
#endif
            chkMatchKey = NO_PATTERN_MATCH;
            return(_TRUE);
        }
        else if (pThis->IP1isPenUp)
        {
            if (!pThis->key1Seg1)
                *chkMatchKey = OMIT_CURRENT_KEY;
            else if (pThis->key1IsDoubleKey)
                *chkMatchKey = DOUBLE_KEYS_TO_SEGMENT_MATCH;
            else
                *chkMatchKey = THIS_SEGMENT_MATCH;
            return(_TRUE);
        }
        else if (pThis->key1IP2 && (pThis->forward || !pThis->key1Seg1))  /* key1 matches IP2 (but not Seg1 if this is a suffix); key2 matches IP1 */
        {
            ET9BOOL    isVowelSwap = (_SWCSearchDB_isVowelKey(pThis, pThis->key1, _TRUE) && _SWCSearchDB_isVowelKey(pThis, pThis->key2, _TRUE));
            ET9BOOL    swapNextOK = (ET9BOOL)((pThis->Z1OperationLevelMax >= Z1_OPERATION_ANY_TRANSPOSE_LEVEL) ||
                                     (isVowelSwap && (pThis->Z1OperationLevelMax >= Z1_OPERATION_VOWEL_TRANSPOSE_LEVEL)));
            if (swapNextOK && !pThis->IP2isPenUp && !doubleKeyMatchesMultiple &&
                (((pThis->keysRemaining > 2) && !pThis->key3IP2 && (!pThis->key3IP1 || !pThis->key2Seg1))
                  || (!pThis->forward && (pThis->keysRemaining == 2)))
                )
            {
                /* If key2 matching is worse than DISTANT_MATCH_THRESHOLD, then confirm that there is a good case for swapping */
                float key2MatchFactor = (float)pThis->ipData->m_IPDistance8[pThis->key2] / (float)pThis->m_backend->pIPTable->IPthreshold8[pThis->ipData->m_IPType][1];
                if (key2MatchFactor > DISTANT_MATCH_THRESHOLD)
                {
                    float   bestMatchFactor = (float)2.0;
                    float   testMatchFactor;
                    if (pThis->key2IP2)
                        bestMatchFactor = (float)pThis->ipData2->m_IPDistance8[pThis->key2] / (float)pThis->m_backend->pIPTable->IPthreshold8[pThis->ipData2->m_IPType][1];   /*lint !e613 */
                    if (pThis->key2Seg2)
                    {
                        testMatchFactor = (float)pThis->seg2Data->m_SegmentDistance8[pThis->key2] / (float)pThis->m_backend->pIPTable->SegmentThreshold8[1];
                        if (testMatchFactor < bestMatchFactor)
                            bestMatchFactor = testMatchFactor;
                    }
                    if (pThis->key2IP3)
                    {
                        testMatchFactor = (float)pThis->ipData3->m_IPDistance8[pThis->key2] / (float)pThis->m_backend->pIPTable->IPthreshold8[pThis->ipData3->m_IPType][1];
                        if (testMatchFactor < bestMatchFactor)
                            bestMatchFactor = testMatchFactor;
                    }
                    if (pThis->key2Seg3)
                    {
                        testMatchFactor = (float)pThis->seg3Data->m_SegmentDistance8[pThis->key2] / (float)pThis->m_backend->pIPTable->SegmentThreshold8[1];
                        if (testMatchFactor < bestMatchFactor)
                            bestMatchFactor = testMatchFactor;
                    }
                    if ((bestMatchFactor / key2MatchFactor) < BETTER_MATCH_THRESHOLD)
                        return(_FALSE);
                }
                *chkMatchKey = NEXT_KEY_IP_MATCH;
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    Log(SWLogger_DEBUG, TEXT(" ...Forcing NEXT_KEY_IP_MATCH for key %d.\n\r"), pThis->keyIndex);
                }
#endif
                return(_TRUE);
            }
        }
    }
    return(_FALSE);
}

/* SavedCodeSegments/SearchDB.cpp/87 - CheckKeyMatches() prior to elimination of Double IPs */

/* SavedCodeSegments/204 - old version of CheckFutureKeyMatches() */
/* SavedCodeSegments/264 - most recent version of CheckFutureKeyMatches() */

/* Determine where key1 should match and set matchKey accordingly */
void ET9FARCALL _SWCSearchDB_CheckKeyMatches(_SWCSearchDB *pThis, SBYTE2 *matchPosIndex, SBYTE2 fixedLimit, ET9BOOL findMatch)
{
    ET9BOOL    validMatch = _FALSE;
    ET9BOOL    seg1SequenceOK, seg2SequenceOK;

    if (!findMatch)
    {
        validMatch = _SWCSearchDB_MatchLocOK(pThis, matchPosIndex, &pThis->matchSlopeDifFactor, &pThis->dualSlopeDifFactor);  /* Make sure current match and previous match are consistent with input path */
        if (!validMatch)
            findMatch = _TRUE;       /* HERE - check whether previous key is the key that should be deleted? */
    }

    if (findMatch)
    {
        pThis->matchKey = NO_PATTERN_MATCH;
        /* SavedCodeSegments/265 - PERFORM_FUTURE_MATCH_CHECK code */
        if (pThis->key1IP1)
        {
            /* See if first key of suffix should skip over a SoftUp */
            if (!pThis->forward && (pThis->keyIndex == 1) && (pThis->ipIndex == 0) && (pThis->ipData->m_IPType == SoftUp) && !pThis->key1IsDoubleKey)
            {
                /*if (pThis->key1IP2 && (pThis->key1IP2 < pThis->key1IP1) && ((!pThis->key2Seg2 && !pThis->key2IP2) || pThis->key2IP3 || pThis->key2Seg3)) */
                if (pThis->key1IP2 && (!pThis->key2IP2 || (pThis->key2IP3 && (pThis->key2IP3 < pThis->key2IP2))) && (!pThis->key2Seg2 || pThis->key2IP3 || (pThis->key2Seg3 && (pThis->key2Seg3 < pThis->key2Seg2))))
                    return;
            }
            pThis->matchKey = IP_MATCH;
            if (pThis->key2IP1)    /* Both key and key2 match current IP; determine best match */
            {
                if (pThis->key1IsDoubleKey)        /* If there is a DoubleLetter at current key... */
                {
                    if (_SWCSearchDB_CheckMultipleIPsMatch(pThis, fixedLimit))
                    {
                        pThis->matchKey = DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH;
                    }
#if CAN_REQUIRE_DOUBLE_GESTURE
                    /* Hold out if there is a possible following Multiple-IPs match (but only if a double gesture is required) */
                    else if (pThis->doubleGestureRequired && pThis->key1IP2 && ((pThis->forward && pThis->ipData2->m_ForwardMultipleCount) || (!pThis->forward && pThis->ipData2->m_BackwardMultipleCount)))
                    {
                        pThis->matchKey = NO_PATTERN_MATCH;
                        return;
                    }
#endif
                    else if (pThis->key1Seg1 &&                                    /* Double key matches current segment */
                             (!pThis->key2IP2 || (pThis->key2IP1 < pThis->key2IP2)) &&           /* key2 either doesn't match IP2, or is better match for IP1 than IP2 */
                             (!pThis->key2Seg2 || (pThis->key2IP1 < pThis->key2Seg2) || (pThis->key2IP1 < pThis->key1IP1)))  /* key2 either doesn't match Seg2, or is better match for IP1, or is better match than key1 */
                    {
                        pThis->matchKey = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                    }
                    else
                    {
                        pThis->matchKey = DOUBLE_KEYS_TO_SINGLE_IP_MATCH;
                    }
                }
                else    /* Not a Double Key */
                {
                    if (pThis->mergedIP)       /* If we are currently at an IP with mergeCount > 1... */
                    {   /* If key2 cannot match next IP or next segment, or if current IP is a better match */
                        if (pThis->ipData2 != NULL)        /* Following tests valid ONLY if ipData2 != NULL */
                        {   /* Don't try multiple match if 2nd key is a double key */
                            if (!pThis->key2IsDoubleKey && (!pThis->key2IP2 || (pThis->key2IP1 < pThis->key2IP2)))
                            {
                                ET9BOOL matchMultiple = (ET9BOOL)(!pThis->key2Seg2 || (pThis->key2IP1 < pThis->key2Seg2));
                                if (!matchMultiple)     /* Make sure potential segment match would be valid */
                                {
                                    SBYTE2  testPosIndex, testLocIndex, currentMatchPos, currentMatchLocIndex;
                                    _SWPoint testLoc, testPos, matchKeyPosDummy;
                                    float   testSlopeDifFactor;
                                    SBYTE2 matchKeyPosIndex3 = 0;
                                    if (pThis->forward)
                                        currentMatchPos = currentMatchLocIndex = pThis->ipData->m_FixedIndexOut;
                                    else
                                        currentMatchPos = currentMatchLocIndex = pThis->ipData->m_FixedIndexIn;
                                    if (pThis->key3IP2)
                                    {
                                        matchKeyPosIndex3 = pThis->ipData2->m_IPPosIndex;
                                    }
                                    else if (pThis->key3Seg2)
                                    {
                                        matchKeyPosIndex3 = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg2Data, pThis->key3, &matchKeyPosDummy, &pThis->matchKeyLoc3, &pThis->matchKeyLocIndex3);
                                    }

                                    testPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg2Data, pThis->key2, &testPos, &testLoc, &testLocIndex);
                                    /* Match to multiple IP if segmatch would be found invalid or if keys matched to same point (by all criteria) */
                                    if (_SWPoint_Equals(&testPos, &pThis->ipData->m_IPLocation) && (testLocIndex == currentMatchLocIndex) && (testPosIndex == currentMatchPos))
                                        matchMultiple = _TRUE;
                                    else
                                        matchMultiple = !_SWCSearchDB_KeysMatchPoints(pThis, pThis->key1, pThis->key2, pThis->key3, _TRUE, pThis->isSwappedKey, _FALSE, pThis->ipData->m_IPLocation, testLoc, currentMatchLocIndex, testLocIndex,
                                                                         pThis->ipData->m_IPLocation, testPos, currentMatchPos, testPosIndex,
                                                                         &testSlopeDifFactor, matchKeyPosIndex3, 0, 0, 0, _TRUE);
                                }
                                if (matchMultiple)
                                    pThis->matchKey = MULTIPLE_KEYS_TO_MERGED_IP_MATCH;
                            }
                        }
                        else    /* If we are currently at the last IP, match current key with segment if that yields a better score */
                        {
                            if (pThis->key1Seg1)
                                pThis->matchKey = THIS_SEGMENT_MATCH;
                            else
                                pThis->matchKey = MULTIPLE_KEYS_TO_MERGED_IP_MATCH;
                        }
                    }
                    /* Not a double Key, and not a DoubleLetter IP (if still set to IP_MATCH), and not PenDown */
                    /* Determine whether key1 should match current segment or current IP */
                    if (pThis->matchKey == IP_MATCH)
                    {
                        SBYTE2 newMatchKeyVal = pThis->matchKey;
                        if (pThis->key1Seg1 && (pThis->keyIndex > 1) && _SWCSearchDB_MatchKey1ToSeg1(pThis, &newMatchKeyVal))
                        {
#if DEBUG_LOG_MATCH_TRACE
                            if (debugThis)
                            {
                                if (newMatchKeyVal == THIS_SEGMENT_MATCH)
                                {
                                    Log(SWLogger_DEBUG, TEXT(" ...Forcing THIS_SEGMENT_MATCH 2 for key %d.\n\r"), pThis->keyIndex);
                                }
                                else if (newMatchKeyVal == OMIT_CURRENT_KEY)
                                {
                                    Log(SWLogger_DEBUG, TEXT(" ...Forcing OMISSION (not SEGMENT_MATCH) 2 for key %d.\n\r"), pThis->keyIndex);
                                }
                                else
                                {
                                    Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 9 for key %d.\n\r"), pThis->keyIndex);
                                }
                            }
#endif
                            pThis->matchKey = newMatchKeyVal;
                            if ((pThis->matchKey == OMIT_CURRENT_KEY) || (pThis->matchKey == NO_PATTERN_MATCH))
                                return;
                        }
                        /* Omit key1 if we are already at PenUp and following key2 can (and must) match it */
                        else if (pThis->IP1isPenUp || (pThis->IP1canBePenUp && !pThis->key2IP2) ||
                                 /* OR if key1 and key2 match ONLY this IP, and key2 is a better match */
                                 ((pThis->key2IP1 < pThis->key1IP1) && !pThis->key1Seg1 && !pThis->key1IP2 && !pThis->key1Seg2 && !pThis->key2Seg1 && !pThis->key2IP2 && !pThis->key2Seg2 && !pThis->key2Seg3 && !pThis->key2IP3))
                        {
                            pThis->matchKey = OMIT_CURRENT_KEY;
                            return;
                        }
                    }
                }
            }
            /* Current key matches current IP; key2 does not.  matchKey already set to IP_MATCH above. */
            else
            {   /* Check for Double-Key and Double-IP special cases */
                SBYTE2 newMatchKeyVal;
                if (pThis->key1IsDoubleKey)        /* If there is a DoubleLetter at current key... */
                {
                    if (_SWCSearchDB_CheckMultipleIPsMatch(pThis, fixedLimit))
                    {
                        pThis->matchKey = DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH;
                    }
#if CAN_REQUIRE_DOUBLE_GESTURE
                    /* Hold out if there is a possible following Multiple-IPs match */
                    else if (pThis->doubleGestureRequired && pThis->key1IP2 && ((pThis->forward && pThis->ipData2->m_ForwardMultipleCount) || (!pThis->forward && pThis->ipData2->m_BackwardMultipleCount)))
                    {
                        pThis->matchKey = NO_PATTERN_MATCH;
                        return;
                    }
#endif
                    else
                    {
                        pThis->matchKey = DOUBLE_KEYS_TO_SINGLE_IP_MATCH;
                    }
                }
                /* If segment is better match (required???), determine whether key1 should match current segment (if not PenDown) */
                /* This is the "rounded 'enough'" case, where the first IP after "n" should actually match the "g" */
                /* Only force match to segment if (1) a following key matches the IP ??? (may actually be "key4" or later ???), and (2) All intervening keys */
                /*   match the current segment, and (3) there is no "natural" match for the following keys with the */
                /*   following IPs / segments */
                else if ((pThis->keyIndex > 1) && pThis->key1Seg1 && (pThis->key1Seg1 < pThis->key1IP1) && _SWCSearchDB_MatchKey1ToSeg1(pThis, &newMatchKeyVal))
                {
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        if (newMatchKeyVal == THIS_SEGMENT_MATCH)
                        {
                            Log(SWLogger_DEBUG, TEXT(" ...Forcing THIS_SEGMENT_MATCH 1 for key %d.\n\r"), pThis->keyIndex);
                        }
                        else
                        {
                            Log(SWLogger_DEBUG, TEXT(" ...Forcing OMISSION (not SEGMENT_MATCH) 1 for key %d.\n\r"), pThis->keyIndex);
                        }
                    }
#endif
                    pThis->matchKey = newMatchKeyVal;
                    if (pThis->matchKey == OMIT_CURRENT_KEY)
                        return;
                }
                /* See if other evidence indicates key1 should be omitted in fovor of key2 segment match */
                else if ((pThis->keyIndex > 1) && pThis->key2Seg1 && _SWCSearchDB_MatchKey2ToSeg1(pThis))
                {
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        Log(SWLogger_DEBUG, TEXT(" ...Forcing OMISSION (not IP_MATCH) 1 for key %d.\n\r"), pThis->keyIndex);
                    }
#endif
                    pThis->matchKey = OMIT_CURRENT_KEY;
                    return;
                }
                /* Check if current key should wait until next IP (if not PenDown) */
                /* If key1 matches IP2 better than IP1 (or IP1 is not a required IP), and we are past the first key and have more IPs than keys remaining */
                else if (pThis->key1IP2 && pThis->forward && (pThis->keyIndex > 1) && (pThis->keysRemaining < pThis->ipsRemaining) && !pThis->IP1canBePenUp &&
                         ((pThis->key1IP2 < pThis->key1IP1) || !pThis->requiredIP) &&
                         (!pThis->key2IP2 || !pThis->key2IP3 || !pThis->key2IsDoubleKey) &&  /* AND key2 is not a Double key matching both following IPs AND */
                         (!pThis->key3IP2 || !pThis->key3IP3 || !pThis->key3IsDoubleKey) &&  /* AND key3 is not a Double key matching both following IPs AND */
                         ( (!pThis->key2IP2 && !pThis->key2Seg2) ||                   /* EITHER: key2 does not match either the following segment or IP, OR */
                           (!pThis->requiredIP &&                              /* IP1 is not required, AND */
                             ((pThis->key2IP3 && ((pThis->key2IP3 < pThis->key2IP2) || !pThis->key3IP3)) ||        /* EITHER key2 matches IP3, and either key2 is a better match for IP3 or key3 does NOT match IP3, OR */
                             (pThis->key2Seg3 && (pThis->key3Seg3 || pThis->key3IP3)))                      /* OR key2 matches segment3, and key3 matches segment 3 or IP3 */
                           )
                         )
                        )
                {
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 6 for key %d.\n\r"), pThis->keyIndex);
                    }
#endif
                    pThis->matchKey = NO_PATTERN_MATCH;
                    return;
                }
                /* test if we are already at PenUp but not at final key - force omission if no segment match possible */
                else if (pThis->IP1isPenUp && (pThis->keysRemaining > 1))
                {
                    if (pThis->key1Seg1)
                        pThis->matchKey = THIS_SEGMENT_MATCH;
                    else
                    {
                        pThis->matchKey = OMIT_CURRENT_KEY;
                        return;
                    }
                }
                else if (pThis->lastKeyMatchesPenUp && (pThis->keysRemaining == 1) && !pThis->IP1canBePenUp)
                {   /* If last key of word matches PenUp, wait for PenUp */
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        Log(SWLogger_DEBUG, TEXT(" ...Forcing key %d to wait for PenUp.\n\r"), pThis->keyIndex);
                    }
#endif
                    pThis->matchKey = NO_PATTERN_MATCH;
                    return;
                }

                /* Special case for two- and three-letter words and two-IPs in path.  Reduce matching score to allow extra "overshoot" */
                /*   factor for high-frequency words, so that, for example, we tend to get "to" tather than "tip" or "top", */
                /*   and "if" or "of" rather than "iud" or "id".  Allow three-letter words so that "our", "out" etc. can compete. */
                /*   Don't apply if path is not relatively straight - allow for tap-dancing on lower-freq words. */
                if (pThis->forward && pThis->IP1isPenUp && (pThis->ipIndex == 1) && (pThis->keysRemaining == 1) &&
                         (pThis->thisWord->length <= 3) && (pThis->thisWord->freqStem >= MIN_TWO_LETTER_HIGH_FREQ) &&
                         (pThis->ipData->m_fLengthRatio <= STRAIGHT_SEGMENT_RATIO))
                {
                    /* Reduce value for key1IP1 */
#if DEBUG_SHOW_MATCH_TRACE && LOGGING
                    BYTE2 savekey1IP1 = pThis->key1IP1;
#endif
                    /* if word is NOT in MAX_FREQ_CLASS */
                    if (pThis->thisWord->freqStem < MAX_FREQ_CLASS)
                    {
                        /* Reduce final key score by 20% - 9%, depending on freq class */
                        BYTE2 reductionFactor = (MAX_FREQ_CLASS + 3) - pThis->thisWord->freqStem;
                        if ((pThis->thisWord->length == 3) && !pThis->key1IsDoubleKey)  /* Lessen reduction for 3-letter words */
                            reductionFactor++;
                        pThis->key1IP1 = (reductionFactor * pThis->key1IP1) / (reductionFactor + 1);
                    }
                    else    /* word is in MAX_FREQ_CLASS */
                    {
                        if (pThis->thisWord->length == 3)
                        {
                            if (!pThis->key1IsDoubleKey)
                                pThis->key1IP1 = (2 * pThis->key1IP1) / 3;            /* Reduce final key score by 33% */
                                /*pThis->key1IP1 = (3 * pThis->key1IP1) / 4;            // Reduce final key score by 25% */
                            else
                                pThis->key1IP1 = (3 * pThis->key1IP1) / 5;            /* Reduce final key score by 40% */
                        }
                        else
                            pThis->key1IP1 = pThis->key1IP1 / 2;                  /* Reduce final key score by 50% if in MAX_FREQ_CLASS and only 2 letters */
                    }
                    pThis->finalKeyScoreAdjusted = _TRUE;
#if DEBUG_SHOW_MATCH_TRACE
                    if (pThis->finalScoringPass)
                        Log(SWLogger_DEBUG,TEXT(" ...Final score adjusted for: %s (%d => %d  seg = %d)\r\n"), pThis->thisWord->externalText, savekey1IP1, pThis->key1IP1, pThis->key1Seg1);
#endif
                }

                /* SavedCodeSegments/SearchDB.cpp/43 */
                if (!pThis->forward)       /* Check for special cases in suffix scoring */
                {
                    /* Check if current key should wait until next IP (if not PenDown) */
                    if (pThis->key1IP2 && !pThis->key1IsDoubleKey && !pThis->requiredIP && (pThis->keyIndex > 1) && (pThis->keysRemaining < pThis->ipsRemaining) && !pThis->IP1canBePenUp &&
                             ((!pThis->key2IP2 && !pThis->key2Seg2) || pThis->key2IP3 || pThis->key2Seg3) )
                    {
#if DEBUG_LOG_MATCH_TRACE
                        if (debugThis)
                        {
                            Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 8 for key %d.\n\r"), pThis->keyIndex);
                        }
#endif
                        pThis->matchKey = NO_PATTERN_MATCH;
                        return;
                    }
                    /* If current key is final key of suffix, check for dual match */
                    if (pThis->finalKey && pThis->key1Seg1 && !pThis->dualMatchSet)
                    {
                        if (!pThis->key1IsDoubleKey)
                            pThis->dualMatch = THIS_SEGMENT_MATCH;
                        else                /* Omit dual segment match if DoubleKey was matched with DoubleLetter IP */
                            pThis->dualMatch = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                        pThis->dualMatchPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key1, &pThis->dualMatchPos, &pThis->dualMatchLoc, &pThis->dualMatchLocIndex);
                    }
                }
            }
        }
        /* Validate current match, if any */
        if ((pThis->matchKey != NO_PATTERN_MATCH) && (pThis->matchKey != OMIT_CURRENT_KEY))
            validMatch = _SWCSearchDB_MatchLocOK(pThis, matchPosIndex, &pThis->matchSlopeDifFactor, &pThis->dualSlopeDifFactor);  /* Make sure current match and previous match are consistent with input path */
        else
            validMatch = _FALSE;
    }
    /* If current key matches current segment but not current IP (don't match to segment if this is the first suffix key */
    /*   and it does not match an initial SoftUp IP that is not a converted Exit IP). */
    if (!validMatch && pThis->key1Seg1 && (pThis->forward || (pThis->keyIndex > 1) || (pThis->ipIndex > 0) || (pThis->ipData->m_IPType != SoftUp) || (pThis->ipData->m_fIPWeight == ExitUpWeight)))
    {
        SBYTE2  checkMatchKey;
        /* test if we are already at PenUp but not at final key - force omission if no segment match possible */
        if (pThis->IP1isPenUp && (pThis->keysRemaining > 1))
        {
            if (pThis->matchKey != THIS_SEGMENT_MATCH)     /* Make sure segment match not already found invalid above */
            {
                if (pThis->key1IsDoubleKey)
                    pThis->matchKey = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                else
                    pThis->matchKey = THIS_SEGMENT_MATCH;
            }
            else
            {
                pThis->matchKey = OMIT_CURRENT_KEY;
                return;
            }
        }
        /* Check whether match for current key should actually wait until next IP. Don't postpone if we are scoring a suffix. */
        else if (pThis->forward && pThis->key1IP2         /* key1 matches following IP */
                         && !pThis->key2IP2        /* key2 does not match following IP */
                         && !pThis->key3IP2        /* key3 does not match following IP */
                         && (!pThis->key4IP2 || ((!pThis->key1Seg1 && !pThis->key2Seg2) || (!pThis->key3Seg1 && !pThis->key3Seg2)))        /* key4 does not match following IP with prior matching opportunities for key2 & key3 */
                         && (!pThis->key2Seg1 || (pThis->key1Seg1PosIndex > pThis->key2Seg1PosIndex))    /* key2 does not match current segment in proper order */
                         && (!pThis->key2Seg2 || ((pThis->ipData->m_IPType != Exit) && !pThis->IP1isArtificial))  /* key2 does not satisfy alternate form of matching "current segment" */
                         && (!pThis->key3IP1 || (pThis->key2Seg2 && pThis->key3IP3))     /* key3 does not match current IP nor do key2/key3 match later in order */
                         && (!pThis->key2IP1 || (pThis->key2IP3 && (3 * pThis->key2IP3 < 5 * pThis->key2IP1) && !pThis->key3IP3))  /* key2 does not match current IP nor have acceptable IP3 match */
                 )
        {
#if DEBUG_LOG_MATCH_TRACE
            if (debugThis)
            {
                Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 7 for key %d.\n\r"), pThis->keyIndex);
            }
#endif
            pThis->matchKey = NO_PATTERN_MATCH;    /* Postpone match till next iteration */
            return;
        }
        else if (pThis->key1IP2 && pThis->key2IP1 && _SWCSearchDB_SwapNextKeyOK(pThis, &checkMatchKey))
        {
            pThis->matchKey = checkMatchKey;
            if ((pThis->matchKey != THIS_SEGMENT_MATCH) && (pThis->matchKey != DOUBLE_KEYS_TO_SEGMENT_MATCH))     /* Need to validate below if segment match */
                return;
        }
        /* Check for segment match prior to shift gesture, where waiting until next segment would prevent a Shift anomaly */
        else if (_SWCSearchDB_MatchKey1AfterExit(pThis))
        {
            pThis->matchKey = NO_PATTERN_MATCH;    /* Postpone match till next iteration */
            return;
        }
        /* Check whether match for current key should actually wait until next segment. */
        else if (!pThis->key2IP1 && pThis->key1Seg2 && (pThis->key1Seg2 < pThis->key1Seg1) &&
                 (!pThis->key2Seg1 ||
                  !_SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex) ||
                  (pThis->key2Seg2 && _SWCSearchDB_PointsInSequenceOrIdentical(pThis, pThis->key1Seg2PosIndex, pThis->key2Seg2PosIndex))
                 ))
        {
            ET9BOOL checkMatch;
            seg1SequenceOK = (ET9BOOL)(pThis->key2Seg1 && (pThis->key1Seg1PosIndex <= pThis->key2Seg1PosIndex));
            seg2SequenceOK = (ET9BOOL)(pThis->key2Seg2 && (pThis->key1Seg2PosIndex <= pThis->key2Seg2PosIndex));
            checkMatch = (ET9BOOL)((!pThis->key2Seg1 || !seg1SequenceOK) && (!pThis->key2Seg2 || seg2SequenceOK));
            if (checkMatch)
            {
                pThis->matchKey = NEXT_SEGMENT_MATCH;
                validMatch = _SWCSearchDB_MatchLocOK(pThis, matchPosIndex, &pThis->matchSlopeDifFactor, &pThis->dualSlopeDifFactor);
                if (validMatch)
                {
                    if (pThis->forward)    /* Don't postpone if we are scoring a suffix. */
                    {
#if DEBUG_LOG_MATCH_TRACE
                        if (debugThis)
                        {
                            Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 5 for key %d.\n\r"), pThis->keyIndex);
                        }
#endif
                        pThis->matchKey = NO_PATTERN_MATCH;    /* Postpone match till next iteration */
                        return;
                    }
                }
            }
            /* Leave double key unmatched if this is a double key that matches a later double IP, or match current key to */
            /*   current segment if it doesn't match the following IP, or if the next key does match the current IP but does */
            /*   not match the following IP or segment, */
            if (pThis->key1IsDoubleKey)
            {
                if ((!pThis->key1IP2 || pThis->key2IP1 || pThis->key2IP2 || (pThis->key2Seg2 && pThis->key3IP2) || (pThis->key2Seg1 && pThis->key3IP1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex))))
                    pThis->matchKey = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                else
                {
                    pThis->matchKey = NO_PATTERN_MATCH;
                    return;
                }
            }
            else
                pThis->matchKey = THIS_SEGMENT_MATCH;

            if (pThis->finalKey && !pThis->forward)   /* If current key is final key of suffix, check for dual match */
            {
                if (!pThis->key1IsDoubleKey)
                    pThis->dualMatch = THIS_SEGMENT_MATCH;
                else                    /* Omit dual segment match if DoubleKey was matched with DoubleLetter IP */
                    pThis->dualMatch = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                if (pThis->dualMatch != NO_PATTERN_MATCH)
                    pThis->dualMatchPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key1, &pThis->dualMatchPos, &pThis->dualMatchLoc, &pThis->dualMatchLocIndex);
            }
            /* See if current key should actually wait to match next IP */
            /*   ??? Also check: pThis->key3IP1, pThis->key3Seg1, pThis->key3IP2, pThis->key3Seg2? */
            if (pThis->forward && (pThis->matchKey == THIS_SEGMENT_MATCH) && pThis->key1IP2)
            {
                ET9BOOL key2MatchesNow = (ET9BOOL)((pThis->key2Seg1 && _SWCSearchDB_PointsInSequenceOrIdentical(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex)) || pThis->key2IP1 || pThis->key2Seg2 || pThis->key2IP2);
                if (!key2MatchesNow)
                {
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 4 for key %d.\n\r"), pThis->keyIndex);
                    }
#endif
                    pThis->matchKey = NO_PATTERN_MATCH;
                    return;
                }
            }
        }   /* ??? else if (pThis->key1IP2 && !pThis->key2IP2 && !pThis->key3IP2 && (!pThis->key2IP1 || (pThis->key2Seg3 && ((2 * pThis->key2Seg3) < pThis->key2IP1)) || ... "aksiom" case? */
        else        /* If no special case applies, try segment match */
        {
            if (pThis->key1IsDoubleKey)
            {
                /* Leave double key unmatched if this is a double key that matches a later double IP (or multiple IPs), or match current key to */
                /*   current segment if it doesn't match the following IP, or if the next key does match the current IP but does */
                /*   not match the following IP or segment, or if there are additional double keys upcoming, or if we are scoring the */
                /*   last letter of a suffix. */
                if (!pThis->key1IP2 || pThis->key2IP1 || pThis->key2IP2 || (pThis->key2Seg2 && pThis->key3IP2) || (pThis->key2Seg1 && pThis->key3IP1 && _SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex)) ||
                    (pThis->nextDoubleKeyIndex < pThis->doubleKeyCount) || (!pThis->forward && pThis->finalKey))
                {
                    pThis->matchKey = DOUBLE_KEYS_TO_SEGMENT_MATCH;
                }
                else
                {
                    pThis->matchKey = NO_PATTERN_MATCH;
                    return;
                }
            }
            /* See if other evidence indicates key1 should be omitted in favor of key2 segment match */
            else if ((pThis->keyIndex > 1) && pThis->key2Seg1 && !_SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex) && _SWCSearchDB_MatchKey2ToSeg1(pThis))
            {
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    Log(SWLogger_DEBUG, TEXT(" ...Forcing OMISSION (not SEGMENT_MATCH) 3 for key %d.\n\r"), pThis->keyIndex);
                }
#endif
                pThis->matchKey = OMIT_CURRENT_KEY;
                return;
            }
            else
            {
                pThis->matchKey = THIS_SEGMENT_MATCH;
            }
        }
        /* Make sure current match and previous match are consistent with input path */
        /* If current key is final key of suffix, check for dual match if not already assigned */
        if (pThis->finalKey && !pThis->forward && !pThis->dualMatchSet &&
            ((pThis->matchKey == THIS_SEGMENT_MATCH) || (pThis->matchKey == DOUBLE_KEYS_TO_SEGMENT_MATCH)))
        {
            /* Confirm validity of segment match */
            pThis->dualMatch = pThis->matchKey;
            pThis->dualMatchPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, pThis->seg1Data, pThis->key1, &pThis->dualMatchPos, &pThis->dualMatchLoc, &pThis->dualMatchLocIndex);
            validMatch = _SWCSearchDB_MatchLocOK(pThis, matchPosIndex, &pThis->matchSlopeDifFactor, &pThis->dualSlopeDifFactor);
            if (!validMatch)
                pThis->matchKey = pThis->dualMatch = NO_PATTERN_MATCH;        /* Reset matchKey and dualMatch in case set above but match was not validated */
        }
        else
        {
            validMatch = _SWCSearchDB_MatchLocOK(pThis, matchPosIndex, &pThis->matchSlopeDifFactor, &pThis->dualSlopeDifFactor);
        }
    }

#if DEBUG_SHOW_MATCH_TRACE
            if (debugThis && (pThis->key1IP1 == 3877))
                pThis->bBreakHere = _TRUE;
#endif
        /* Check following key if current key is not consistent with input path */
    if (!validMatch)
    {
        pThis->matchKey = NO_PATTERN_MATCH;             /* Reset matchKey and dualMatch in case set above but match was not validated */
        if (!pThis->dualMatchSet)
            pThis->dualMatch = NO_PATTERN_MATCH;        /* Reset matchKey and dualMatch in case set above but match was not validated */
        if ((pThis->key1IP1 || pThis->key1Seg1) && (pThis->isSwappedKey || pThis->wasSwappedKey))
        {
#if DEBUG_LOG_MATCH_TRACE
            if (debugThis)
            {
                Log(SWLogger_DEBUG, TEXT(" ...Forcing OMIT_TRANSPOSED_KEY for key %d.\n\r"), pThis->keyIndex);
            }
#endif
            /* Force omission of transposed key */
            pThis->matchKey = OMIT_TRANSPOSED_KEY;
            return;
        }
        /* Can't omit or transpose first key or transpose Double key; don't transpose if we know we already need to omit key */
        else if (pThis->keyIndex > 1)
        {
            if (pThis->key2IP1)    /* If key2 matches current IP return flag signaling possible match */
            {
                SBYTE2 checkMatchKey;
                if (!pThis->key1IsDoubleKey && !pThis->key2IsDoubleKey && _SWCSearchDB_SwapNextKeyOK(pThis, &checkMatchKey))
                {
                    pThis->matchKey = checkMatchKey;
                    if ((pThis->matchKey == THIS_SEGMENT_MATCH) || (pThis->matchKey == DOUBLE_KEYS_TO_SEGMENT_MATCH))
                    {
                        validMatch = _SWCSearchDB_MatchLocOK(pThis, matchPosIndex, &pThis->matchSlopeDifFactor, &pThis->dualSlopeDifFactor);
                        if (!validMatch)
                        {
                            pThis->matchKey = pThis->dualMatch = NO_PATTERN_MATCH;        /* Reset matchKey and dualMatch if segment match was not validated */
                            return;
                        }
                        DebugAssert(pThis->forward || !pThis->finalKey);
                        /*else if (!pThis->forward && pThis->finalKey) */
                        /*    pThis->dualMatch = THIS_SEGMENT_MATCH; */
                    }
                }
                else
                {
                    /* Check whether current key should simply be omitted... */
                    if (pThis->key3Seg2 || pThis->key3IP2 || (pThis->key2IsDoubleKey && pThis->key2IP2 && (pThis->key2IP3 || pThis->key3Seg3 || pThis->key3IP3 || (pThis->ipData3 == NULL))))
                    {
                        pThis->matchKey = OMIT_CURRENT_KEY;
#if DEBUG_LOG_MATCH_TRACE
                        if (debugThis)
                        {
                            Log(SWLogger_DEBUG, TEXT(" ...Forcing OMIT_CURRENT_KEY 1 for key %d.\n\r"), pThis->keyIndex);
                        }
#endif
                    }
                    return;
                }
            }
            else if (pThis->key1Seg2 && pThis->key2IP2 && (pThis->key3Seg3 || pThis->key3IP3 || (pThis->key3 == SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))))  /* If key1 matches next segment and key2 matches the following IP, */
            {                                                                       /*   and key3 matches following segment or IP, then delay match... */
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 2 for key %d.\n\r"), pThis->keyIndex);
                }
#endif
                pThis->matchKey = NO_PATTERN_MATCH;
                return;
            }
            else
            {
                /* Check whether matching should be delayed in order to match next key to an otherwise-unmatched next IP, without */
                /*   skipping over an upcoming matching opportunity for the current key */
                if ( (pThis->key2IP2 && (!pThis->key1Seg2 || !_SWCSearchDB_PointsInSequence(pThis, pThis->key1Seg2PosIndex, pThis->key2Seg2PosIndex)) && (!pThis->key1IP2 || pThis->IP2isPenUp)) ||
                     (pThis->key1IP2 && (pThis->key2Seg3 || pThis->key2IP3)) ||
                      _SWCSearchDB_MatchKey1AfterExit(pThis) || _SWCSearchDB_MatchKey1AfterPathDivision(pThis) )
                {
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        Log(SWLogger_DEBUG, TEXT(" ...Forcing NO_PATTERN_MATCH 1 for key %d.\n\r"), pThis->keyIndex);
                    }
#endif
                    pThis->matchKey = NO_PATTERN_MATCH;
                    return;
                }
                else if (pThis->key2Seg1)  /* If key2 matches current segment return flag signaling possible match */
                {
#if DEBUG_LOG_MATCH_TRACE
                    if (debugThis)
                    {
                        Log(SWLogger_DEBUG, TEXT(" ...Forcing/Flagging case for NEXT_KEY_SEGMENT_MATCH for key %d.\n\r"), pThis->keyIndex);
                    }
#endif
                    pThis->matchKey = NEXT_KEY_SEGMENT_MATCH;
                    return;
                }
            }
        }
    }
    /* If current match and previous match are consistent with input path, then update lastKey data */
    if (validMatch && (pThis->matchKey != NO_PATTERN_MATCH) && (pThis->matchKey != OMIT_CURRENT_KEY))         /* Wait till current key actually matched */
    {
        /* DEBUG breakpoint */
        if (pThis->matchKeyPosIndex < 0)
            pThis->matchKeyPosIndex = 0;
        else if (pThis->matchKeyPosIndex >= _SWCSearchDB_GetZ1FixedDataSize(pThis))
            pThis->matchKeyPosIndex = _SWCSearchDB_GetZ1FixedDataSize(pThis) - 1;
            /* Set matchPosIndex[] location for key */
        matchPosIndex[pThis->keyIndex - 1] = pThis->matchKeyPosIndex; /* Assume no relevant shift flag set */
        pThis->matchLocExitIndex[pThis->keyIndex - 1] = pThis->matchKeyLocExitIndex; /* Assume no relevant shift flag set */

        pThis->lastKey = pThis->key1;         /* Save new values as lastKey */
        pThis->lastMatchKeyLoc = pThis->matchKeyLoc;
        pThis->lastMatchKeyPos = pThis->matchKeyPos;
        pThis->lastMatchKeyLocIndex = pThis->matchKeyLocExitIndex;
        pThis->lastMatchKeyPosIndex = pThis->matchKeyPosIndex;
        pThis->altLastMatchKeyLoc = pThis->altMatchKeyLoc;
        pThis->altLastMatchKeyPos = pThis->altMatchKeyPos;
        pThis->altLastMatchKeyLocIndex = pThis->altMatchKeyLocExitIndex;
        pThis->altLastMatchKeyPosIndex = pThis->altMatchKeyPosIndex;
        pThis->altLastMatchKeyType = pThis->altMatchKeyType;
        pThis->altLastMatchKeyRawScore = pThis->altMatchKeyRawScore;
        pThis->altLastMatchKeyRawDist = pThis->altMatchKeyRawDist;
        pThis->altLastMatchKeyWeightSum = pThis->altMatchKeyWeightSum;
        pThis->altLastMatchKeyHasSegmentMatch = pThis->altMatchKeyHasSegmentMatch;
        if (!pThis->exitLoop)      /* Don't bother with further testing if test above already failed... */
        {
            if ((pThis->matchKey == MULTIPLE_KEYS_TO_MERGED_IP_MATCH) && (pThis->key2 < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm)))
            {
                pThis->lastKey = pThis->key2;         /* Save last matched key as lastKey */
                matchPosIndex[pThis->keyIndex] = pThis->matchKeyPosIndex;
                pThis->matchLocExitIndex[pThis->keyIndex] = pThis->matchKeyLocExitIndex;
            }
        }
    }
}   /* void _SWCSearchDB_CheckKeyMatches() */


/* Look at preceding key K1 and following key K3 with respect to segment match key K2 (at */
/* match locations M1, M2 and M3 respectively.  Compare ratio of (K1->K2)+(K2->K3)/(K1->K3) */
/* to (M1->M3)(path)/(M1->M3)(straight line), and increase the slope factor when */
/* this ratio is greater than 1.0.  Use slopeKeyIndex to reference next key in case current key */
/* is a double key.  This adjustment is intended for when the path is a relatively straight line. */
/* If the curvature of the path segment exceeds the test threshold, then do not adjust the slope factor. */
float ET9FARCALL _SWCSearchDB_AdjustSegmentSlopeFactor(_SWCSearchDB *pThis, SBYTE2 *matchPosIndex, SBYTE2 thisKeyIndex, SBYTE2 nextKeyIndex, float initialValue)
{
    BYTE4 K1K2Dist, K2K3Dist, K1K3Dist;
    _SWPoint KP1, KP2, KP3;
    BYTE4 M1M3PathLen, M1M3Dist;
    float keyRatio, matchRatio, segmentRatio;

    ET9BOOL matchSequenceOK = (!_SWCSearchDB_InvalidPosIndex(pThis, matchPosIndex[thisKeyIndex - 1]) && !_SWCSearchDB_InvalidPosIndex(pThis, matchPosIndex[nextKeyIndex]) &&
                            _SWCSearchDB_PointsInSequenceOrIdentical(pThis, matchPosIndex[thisKeyIndex - 1], matchPosIndex[nextKeyIndex]));
    segmentRatio = (float)1.0;      /* Init to default value */

    if (!matchSequenceOK)
    {
        if (segmentRatio > MAX_SLOPE_FACTOR_ADJUSTMENT)
            segmentRatio = MAX_SLOPE_FACTOR_ADJUSTMENT;
        if (initialValue > (float)1.0)
            initialValue = (float)1.0 + ((initialValue - (float)1.0) * MAX_SLOPE_FACTOR_ADJUSTMENT);
        else
            initialValue = MAX_SLOPE_FACTOR_ADJUSTMENT;
        return(initialValue);
    }
    M1M3PathLen = _SWCSearchDB_GetZ1PathLengthPrecise(pThis, matchPosIndex[thisKeyIndex - 1], matchPosIndex[nextKeyIndex]);
    M1M3Dist = _SWPoint_preciseDistance_PP(_SWCSearchDB_GetZ1FixedPoint(pThis, matchPosIndex[thisKeyIndex - 1]), _SWCSearchDB_GetZ1FixedPoint(pThis, matchPosIndex[nextKeyIndex]));
    if (M1M3Dist > 0)
    {
        matchRatio = (float)M1M3PathLen / (float)M1M3Dist;
        if (matchRatio <= STRAIGHT_SEGMENT_RATIO)
        {
            SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->keys[thisKeyIndex - 1], &KP1);
            SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->keys[thisKeyIndex], &KP2);
            SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->keys[nextKeyIndex], &KP3);
            K1K2Dist = _SWPoint_preciseDistance_PP(KP1, KP2);
            K2K3Dist = _SWPoint_preciseDistance_PP(KP2, KP3);
            K1K3Dist = _SWPoint_preciseDistance_PP(KP1, KP3);
            if (K1K3Dist > 0)
            {

                keyRatio = (float)(K1K2Dist + K2K3Dist) / (float)K1K3Dist;
                if (keyRatio > matchRatio)
                {
                    /* Adjust by (keyRatio - 1.0) / (matchRatio - 1.0) */
                    if ((keyRatio > (float)1.0) && (matchRatio > (float)1.0))
                    {
                        segmentRatio = (keyRatio - (float)1.0) / (matchRatio - (float)1.0);
                    }
                    else
                    {
                        segmentRatio = keyRatio / matchRatio;
                    }
                    if (segmentRatio > MAX_SLOPE_FACTOR_ADJUSTMENT)
                        segmentRatio = MAX_SLOPE_FACTOR_ADJUSTMENT;
                    if (initialValue > (float)1.0)
                        initialValue = (float)1.0 + ((initialValue - (float)1.0) * segmentRatio);
                }
            }
        }
    }
    return(initialValue);
}   /* void _SWCSearchDB_AdjustSegmentSlopeFactor() */


#if DEBUG_LOG_MATCH_TRACE

void ET9FARCALL _SWCSearchDB_DebugTraceWordMGD(_SWCSearchDB *pThis, _SWWord *dbWord, float skipPenalty, ET9BOOL passed, SBYTE2 lastKeyScored)
{
    ET9SYMB sufChar;
    BYTE1   key;
    SBYTE2  keyIndexx, doubleOffset, wordLen, keysLen;
    SBYTE2  omissionEvents = 0;
    _SWPoint keyLoc, charLoc;
    CPOS charIndexx = 0;

    ET9_UNUSED(skipPenalty);

    Log(SWLogger_DEBUG,TEXT("DebugTraceWordMGD\n"));

    wordLen = (SBYTE2)dbWord->textLen;
    keyIndexx = 0;
    keysLen = (SBYTE2)dbWord->length;
    keyIndexx = 0;
    if (pThis->finalScoringPass)
    {
        Log(SWLogger_DEBUG,TEXT(" FINAL Pass: "));
    }
    else
    {
        Log(SWLogger_DEBUG,TEXT(" INITIAL Pass: "));
    }
    if (passed)
    {
        Log(SWLogger_DEBUG,TEXT(" PASSED \n"));
    }
    else
    {
        Log(SWLogger_DEBUG,TEXT(" FAILED \n"));
    }
    Log(SWLogger_DEBUG,TEXT(" *** Word: %s  WI: %d  CS: %.4e  NPSS: %f  "), dbWord->externalText, dbWord->wordIndex, dbWord->combinedScore, dbWord->noPenaltyScoreSort);
    Log(SWLogger_DEBUG,TEXT(" NPS: %f  FS: %.4e  FG: %d  FStem: %d"), dbWord->noPenaltyScore, dbWord->finalScore, dbWord->freqGroup, dbWord->freqStem);
    Log(SWLogger_DEBUG,TEXT("   OC/TC/VTC/SKIP: %d/%d/%d/%d  SP:%f \n"), dbWord->omitCount, dbWord->transposeCount, pThis->vowelTransposeCount, dbWord->skippedIPs, dbWord->skipPenalty);
    Log(SWLogger_DEBUG,TEXT(" *** Word: %s  AD: %f  PAD: %f  AS: %f  "), dbWord->externalText, dbWord->avDistance, dbWord->penaltyAvDistance, dbWord->avScore);
    Log(SWLogger_DEBUG,TEXT(" PAS: %f  RS: %d  WS: %f  SS: %f (ASF: %f))\n"), dbWord->penaltyAvScore, dbWord->rawScore, dbWord->weightSum, dbWord->slopeScore, dbWord->avSlopeFactor);
    for (keyIndexx = 0; (keyIndexx < pThis->keySeqLength) && (keyIndexx < lastKeyScored); keyIndexx++)
    {
        sufChar = dbWord->externalText[charIndexx++];
        if (!sufChar)       /* May reach end of word if error */
        {
            sufChar = '>';      /* Flag that we are past the end of the word text */
            charIndexx--;
        }
        key = pThis->keys[keyIndexx];
        SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, key, &keyLoc);
        doubleOffset = 0;
        /* Output omission, transposition info */
        while ((omissionEvents < dbWord->omissionCount) && (keyIndexx == (dbWord->omitKeys[omissionEvents] - omissionEvents)))
        {
            BYTE1 charKey = SWDbm_charToKey(pThis->m_backend->m_pDbm, sufChar);
            SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, charKey, &charLoc);
            Log(SWLogger_DEBUG,TEXT(" OMITTED => %c [%d @ %d,%d] \n"), sufChar, charKey, charLoc.x, charLoc.y);
            if (dbWord->omitCounts[omissionEvents] > 1)
            {
                sufChar = dbWord->externalText[charIndexx++];
                charKey = SWDbm_charToKey(pThis->m_backend->m_pDbm, sufChar);
                SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, charKey, &charLoc);
                Log(SWLogger_DEBUG, TEXT(" OMITTED => %c [%d @ %d,%d] \n"), sufChar, charKey, charLoc.x, charLoc.y);
            }
            omissionEvents++;
            sufChar = dbWord->externalText[charIndexx++];
        }
        if ((pThis->keyFlags[keyIndexx] == TRANSPOSED_PREV) || (pThis->keyFlags[keyIndexx] == TRANSPOSED_PREV_ONLY))
        {
            Log(SWLogger_DEBUG, TEXT(" SWAP PREV => "));
        }
        else if (pThis->keyFlags[keyIndexx] == TRANSPOSED_NEXT)
        {
            Log(SWLogger_DEBUG, TEXT(" SWAP NEXT => "));
        }

        {
            /* Output key and match type info */
            SBYTE2 matchIndex = 0;
            SBYTE2 thisMatchKey = st[keyIndexx].matchKey;
            switch (thisMatchKey)
            {
            case NO_PATTERN_MATCH:
                Log(SWLogger_DEBUG,TEXT(" SKIP => "));
                break;
            case DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH:
            case MULTIPLE_KEYS_TO_MERGED_IP_MATCH:
            case DOUBLE_KEYS_TO_SINGLE_IP_MATCH:
            case DOUBLE_KEYS_TO_SEGMENT_MATCH:
                Log(SWLogger_DEBUG,TEXT(" %c [%d @ %d,%d]"), sufChar, key, keyLoc.x, keyLoc.y);
                sufChar = dbWord->externalText[charIndexx++];
                if (!sufChar)       /* May reach end of word if error */
                {
                    sufChar = '>';      /* Flag that we are past the end of the word text */
                    charIndexx--;
                }
                matchIndex = st[keyIndexx].ipIndex - 1;
                if (thisMatchKey == MULTIPLE_KEYS_TO_MERGED_IP_MATCH)
                {
                    key = pThis->keys[keyIndexx++];
                    SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, key, &keyLoc);
                }
                Log(SWLogger_DEBUG,TEXT("  + %c [%d @ %d,%d] => "), sufChar, key, keyLoc.x, keyLoc.y);
                switch (thisMatchKey)
                {
                case DOUBLE_KEYS_TO_SINGLE_IP_MATCH:
                    matchIndex = sw_max(0, st[keyIndexx].ipIndex - 1);
                    if ((matchIndex < pThis->m_wIPTableCount) && (pThis->m_aIPTable[matchIndex]->m_MergeCount > 1))
                    {
                        Log(SWLogger_DEBUG,TEXT(" DOUBLE_TO_MERGED_IP "));
                    }
                    else
                    {
                        Log(SWLogger_DEBUG,TEXT(" DOUBLE_TO_SINGLE "));
                    }
                    break;
                case DOUBLE_KEYS_TO_SEGMENT_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" DOUBLE_TO_SEGMENT "));
                    break;
                case MULTIPLE_KEYS_TO_MERGED_IP_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" MULTIPLE_TO_MERGED_IP "));
                    break;
                case DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" DOUBLE_TO_MULTIPLE_IPS "));
                    break;
                }
                break;
            default:
                Log(SWLogger_DEBUG,TEXT(" %c [%d @ %d,%d] => "), sufChar, key, keyLoc.x, keyLoc.y);
                switch (st[keyIndexx].matchKey)
                {
                case IP_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" IP_MATCH "));
                    break;
                case THIS_SEGMENT_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" SEGMENT_MATCH "));
                    break;
                case NEXT_SEGMENT_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" NEXT_SEGMENT_MATCH ??? "));
                    break;
                case DUAL_MATCH:
                    Log(SWLogger_DEBUG,TEXT(" DUAL_MATCH ??? "));
                    break;
                default:
                    Log(SWLogger_DEBUG,TEXT(" ??? (%d) "), st[keyIndexx].matchKey);
                    break;
                }
                break;
            }
        }
        /* Output IP or Segment info */
        if ((st[keyIndexx].matchKey != THIS_SEGMENT_MATCH) && (st[keyIndexx].matchKey != NEXT_SEGMENT_MATCH) &&
            (st[keyIndexx].matchKey != DOUBLE_KEYS_TO_SEGMENT_MATCH))
        {
            switch (st[keyIndexx].p_IPType)
            {
            case Tap:
                Log(SWLogger_DEBUG,TEXT(" Tap"));
                break;
            case PenDown:
                Log(SWLogger_DEBUG,TEXT(" PenDown"));
                break;
            case SoftDown:
                Log(SWLogger_DEBUG,TEXT(" SoftDown"));
                break;
            case Pause:
                Log(SWLogger_DEBUG,TEXT(" Pause"));
                break;
            case PauseAngle:
                Log(SWLogger_DEBUG,TEXT(" PauseAngle"));
                break;
            case Multiple:
                Log(SWLogger_DEBUG,TEXT(" Multiple"));
                break;
            case DoubleLetter:
                Log(SWLogger_DEBUG,TEXT(" DoubleLetter"));
                doubleOffset = 1;
                break;
            case PenUp:
                Log(SWLogger_DEBUG,TEXT(" PenUp"));
                break;
            case SoftUp:
                Log(SWLogger_DEBUG,TEXT(" SoftUp"));
                break;
            case Angle:
                Log(SWLogger_DEBUG,TEXT(" Angle"));
                break;
            case PathDivision:
                Log(SWLogger_DEBUG,TEXT(" PathDivision"));
                break;
            default:
                break;
            }
            Log(SWLogger_DEBUG,TEXT("  %d"), st[keyIndexx].ipIndex);
            if (st[keyIndexx].matchKey == DUAL_MATCH)
                Log(SWLogger_DEBUG,TEXT("  and Segment"));
        }
        else
            Log(SWLogger_DEBUG,TEXT(" Segment %d"), st[keyIndexx].ipIndex);
        /* Output matching position */
        Log(SWLogger_DEBUG,TEXT("  @ [%d, %d](%d) from %d/8, "), st[keyIndexx].matchKeyPos.x, st[keyIndexx].matchKeyPos.y, st[keyIndexx].matchKeyIndex, pThis->rawDistKey[keyIndexx]);
        if (pThis->slopeFactorKey[keyIndexx] > 0.0)
        {
            Log(SWLogger_DEBUG,TEXT("  for %d * %f / %f]"), pThis->rawScoreKey[keyIndexx], pThis->slopeFactorKey[keyIndexx], pThis->weightSumKey[keyIndexx]);
        }
        else
        {
            Log(SWLogger_DEBUG,TEXT("  for %d * %f(=ASF) / %f]"), pThis->rawScoreKey[keyIndexx], dbWord->avSlopeFactor, pThis->weightSumKey[keyIndexx]);
        }
        if (pThis->skipPenaltyKey[keyIndexx] > 0.0)
        {
            Log(SWLogger_DEBUG,TEXT("  SP: %f \n"), pThis->skipPenaltyKey[keyIndexx]);
        }
        else
        {
            Log(SWLogger_DEBUG,TEXT("  \n"));
        }
    }
    if (lastKeyScored < pThis->keySeqLength)
        Log(SWLogger_DEBUG,TEXT(" (Remaining %d unique keys of word NOT re-scored) \n"), (pThis->keySeqLength - lastKeyScored));
}

#endif

BYTE2 ET9FARCALL _SWCSearchDB_SetSegmentDistancePosition(_SWCSearchDB *pThis, SWCIPTableRow *segData, BYTE1 key, SBYTE2 fixedLimit, SBYTE2 *posIndex)
{
    if (key < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))
    {
        BYTE2   KeyDistance = _SWCSearchDB_GetSegmentWDistance(pThis, segData, key, fixedLimit);
        if (KeyDistance)
        {
            *posIndex = segData->m_LinePos[key];
            if (*posIndex == IPT_NO_MATCH)
                *posIndex = 0;
            else
            {
                if (*posIndex == 0)
                    *posIndex = 1;           /* Make sure any valid index is non-zero */
            }
        }
        else
            *posIndex = 0;
        return(KeyDistance);
    }
    *posIndex = 0;           /* Invalid key */
    return(0);
}


void ET9FARCALL _SWCSearchDB_SetKeyDistancesFromKeyRepeats(_SWCSearchDB *pThis, SBYTE2 fixedLimit)
{
    SBYTE2  nextKeyIndex;
    _SWPoint keyLoc;

#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis)
        pThis->bBreakHere = _TRUE;
#endif

    pThis->requiredIP = _SWCSearchDB_IsRequiredIP(pThis->ipData);
    if (pThis->ipData->m_MergeCount > 1)
        pThis->mergedIP = pThis->ipData->m_MergeCount;
    else
        pThis->mergedIP = 0;

    pThis->advanceIP = _FALSE;
    pThis->advanceKey = _TRUE;
    pThis->thisKeyCheckAlternateMatches = pThis->nextKeyCheckAlternateMatches;
    pThis->nextKeyCheckAlternateMatches = _FALSE;
    pThis->ipIndexKey[pThis->keyIndex] = pThis->ipIndex;     /* Record position in IP table when key is processed */

    pThis->key1 = pThis->keys[pThis->keyIndex];
    pThis->key1IsDoubleKey = (pThis->m_keyRepeats[pThis->keyIndex] > 0);
    if (pThis->key1IsDoubleKey)        /* Track as each double key in word is processed */
        pThis->nextDoubleKeyIndex++;
    SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->key1, &keyLoc);        /* Get location of key */
    if (keyLoc.x < pThis->wordMinX)
        pThis->wordMinX = keyLoc.x;
    if (keyLoc.x > pThis->wordMaxX)
        pThis->wordMaxX = keyLoc.x;
    if (keyLoc.y < pThis->wordMinY)
        pThis->wordMinY = keyLoc.y;
    if (keyLoc.y > pThis->wordMaxY)
        pThis->wordMaxY = keyLoc.y;

    pThis->isSwappedKey = (ET9BOOL)(((pThis->keyIndex + 1) < pThis->keySeqLength) && ((pThis->keyFlags[pThis->keyIndex + 1] == TRANSPOSED_PREV) || (pThis->keyFlags[pThis->keyIndex + 1] == TRANSPOSED_PREV_ONLY)));
    if (!pThis->isSwappedKey && (pThis->keyIndex >= 1))
        pThis->isSwappedKey = ((pThis->keyFlags[pThis->keyIndex - 1] == TRANSPOSED_NEXT) || ((pThis->keyFlags[pThis->keyIndex] != NO_CHANGE) && (pThis->keyFlags[pThis->keyIndex] != OMIT_KEY_LATER)));
    if (pThis->keyIndex > 0)
    {
        pThis->wasSwappedKey = (ET9BOOL)((pThis->keyIndex < pThis->keySeqLength) && ((pThis->keyFlags[pThis->keyIndex] == TRANSPOSED_PREV) || (pThis->keyFlags[pThis->keyIndex] == TRANSPOSED_PREV_ONLY)));
        if (!pThis->wasSwappedKey && (pThis->keyIndex >= 1))
            pThis->wasSwappedKey = ((pThis->keyFlags[pThis->keyIndex - 1] != NO_CHANGE) && (pThis->keyFlags[pThis->keyIndex - 1] != OMIT_KEY_LATER));
        if (!pThis->wasSwappedKey && (pThis->keyIndex >= 2))
            pThis->wasSwappedKey = (pThis->keyFlags[pThis->keyIndex - 2] == TRANSPOSED_NEXT);
    }
    else
        pThis->wasSwappedKey = _FALSE;
    /* Note: Keep calls to SetSegmentDistancePosition() and GetIPWDistance() in correct sequence so that keyMatch[][FIRST_MATCH] is set correctly */
    pThis->keyIndexM1 = pThis->keyIndex;           /* Set keyIndexM1 for frequent access to [keyIndex - 1] array elements */
    pThis->keyIndex++;     /* Advance to next key */
    nextKeyIndex = pThis->key2Index = pThis->keyIndex;
    if (nextKeyIndex < pThis->keySeqLength)
    {
        pThis->key2 = pThis->keys[nextKeyIndex];
        pThis->key2IsDoubleKey = (pThis->m_keyRepeats[nextKeyIndex++] > 0);
        pThis->key3Index = nextKeyIndex;
        if (nextKeyIndex < pThis->keySeqLength)
        {
            pThis->key3 = pThis->keys[nextKeyIndex];
            pThis->key3IsDoubleKey = (pThis->m_keyRepeats[nextKeyIndex++] > 0);
        }
        else
        {
            pThis->key3 = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
            pThis->key3IsDoubleKey = _FALSE;
        }
    }
    else
    {
        pThis->key2 = pThis->key3 = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
        pThis->key2IsDoubleKey = pThis->key3IsDoubleKey = _FALSE;
    }
    pThis->IP1isPathDivision = (ET9BOOL)(pThis->ipData->m_IPType == PathDivision);
    pThis->IP1isMultiple = (ET9BOOL)(pThis->ipData->m_IPType == Multiple);
    pThis->IP1isArtificial = pThis->IP1isPathDivision || pThis->IP1isMultiple;
    pThis->key1Seg1 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg1Data, pThis->key1, fixedLimit, &pThis->key1Seg1PosIndex);
    pThis->key1IP1 = (pThis->IP1isPathDivision || (pThis->IP1isMultiple && !pThis->key1IsDoubleKey)) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData, pThis->key1);
    pThis->key1Seg2 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg2Data, pThis->key1, fixedLimit, &pThis->key1Seg2PosIndex);
    pThis->IP1isPenUp = pThis->IP1canBePenUp = (ET9BOOL)((pThis->forward) ? ((pThis->ipData->m_IPType == PenUp) || (pThis->ipData->m_IPType == SoftUp)) : (pThis->ipData->m_IPType == PenDown));
    pThis->finalKey = (ET9BOOL)(pThis->keyIndex == pThis->keyLimit);
    pThis->keysRemaining = (pThis->keySeqLength - pThis->keyIndex) + 1;        /* Including current key, number of keys remaining in word */

    pThis->key2Seg1 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg1Data, pThis->key2, fixedLimit, &pThis->key2Seg1PosIndex);
    if ((pThis->ipIndex > 0) || pThis->key1IsDoubleKey || pThis->mergedIP)     /* No "this" segment for PenDown location. key2 CANNOT match PenDown since first */
        pThis->key2IP1 = (pThis->IP1isMultiple && !pThis->key2IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData, pThis->key2);     /*   key of word MUST match it (unless first key is double or first IP is multiple). */
    else
        pThis->key2IP1 = 0;
    pThis->key2Seg2 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg2Data, pThis->key2, fixedLimit, &pThis->key2Seg2PosIndex);

    pThis->key3Seg1 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg1Data, pThis->key3, fixedLimit, &pThis->key3Seg1PosIndex);
    if (pThis->ipIndex > 0)                                    /* No "this" segment for PenDown location. key3 CANNOT match PenDown since first */
        pThis->key3IP1 = (pThis->IP1isMultiple && !pThis->key3IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData, pThis->key3); /*   key of word MUST match it */
    else
        pThis->key3IP1 = 0;
    pThis->key3Seg2 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg2Data, pThis->key3, fixedLimit, &pThis->key3Seg2PosIndex);
    /* Special case: If two or more of key1, key2 and key3 all match segment 1, check for following key matching IP1, Seg1, IP2 or Seg2 */
    pThis->key4 = (nextKeyIndex < pThis->keySeqLength) ? pThis->keys[nextKeyIndex] : SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
    if (pThis->key4 < SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm))
    {
        pThis->key4IsDoubleKey = (pThis->m_keyRepeats[nextKeyIndex] > 0);
        pThis->key4IP1 = (pThis->IP1isMultiple && !pThis->key4IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData, pThis->key4);
        pThis->key4Seg1 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg1Data, pThis->key4, fixedLimit, &pThis->key4Seg1PosIndex);
        pThis->key4Seg2 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg2Data, pThis->key4, fixedLimit, &pThis->key4Seg2PosIndex);
    }
    else
    {
        pThis->key4IP1 = pThis->key4Seg1 = pThis->key4Seg2 = 0;
        pThis->key4IsDoubleKey = _FALSE;
    }
    if ((pThis->ipIndex + 1) < pThis->m_wIPTableCount)
    {
        pThis->ipData2 = pThis->m_aIPTable[pThis->ipIndex + 1];
        pThis->IP2isPathDivision = (ET9BOOL)(pThis->ipData2->m_IPType == PathDivision);
        pThis->IP2isMultiple = (ET9BOOL)(pThis->ipData2->m_IPType == Multiple);
        pThis->IP2isArtificial = pThis->IP2isPathDivision || pThis->IP2isMultiple;
        pThis->key1IP2 = (pThis->IP2isMultiple && !pThis->key1IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData2, pThis->key1);
        pThis->key2IP2 = (pThis->IP2isMultiple && !pThis->key2IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData2, pThis->key2);
        pThis->key3IP2 = (pThis->IP2isMultiple && !pThis->key3IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData2, pThis->key3);
        pThis->key4IP2 = (pThis->IP2isMultiple && !pThis->key4IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData2, pThis->key4);
        pThis->IP2isPenUp = (ET9BOOL)((pThis->forward) ? ((pThis->ipData2->m_IPType == PenUp) || (pThis->ipData2->m_IPType == SoftUp)) : (pThis->ipData2->m_IPType == PenDown));
        if (pThis->forward && (pThis->ipData2->m_IPType == SoftUp))
            pThis->IP1canBePenUp = _TRUE;
    }
    else
    {
        pThis->ipData2 = NULL;
        pThis->key1IP2 = pThis->key2IP2 = pThis->key3IP2 = pThis->key4IP2 = 0;
        pThis->IP2isPenUp = _FALSE;
        pThis->IP2isPathDivision = pThis->IP2isMultiple = pThis->IP2isArtificial = _TRUE;
    }
    pThis->key1Seg3 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg3Data, pThis->key1, fixedLimit, &pThis->key1Seg3PosIndex);
    pThis->key2Seg3 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg3Data, pThis->key2, fixedLimit, &pThis->key2Seg3PosIndex);
    pThis->key3Seg3 = _SWCSearchDB_SetSegmentDistancePosition(pThis, pThis->seg3Data, pThis->key3, fixedLimit, &pThis->key3Seg3PosIndex);
    if ((pThis->ipIndex + 2) < pThis->m_wIPTableCount)
    {
        pThis->ipData3 = pThis->m_aIPTable[pThis->ipIndex + 2];
        pThis->IP3isPathDivision = (ET9BOOL)(pThis->ipData3->m_IPType == PathDivision);
        pThis->IP3isMultiple = (ET9BOOL)(pThis->ipData3->m_IPType == Multiple);
        pThis->IP3isArtificial = pThis->IP3isPathDivision || pThis->IP3isMultiple;
        pThis->key1IP3 = (pThis->IP3isMultiple && !pThis->key1IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData3, pThis->key1);
        pThis->key2IP3 = (pThis->IP3isMultiple && !pThis->key2IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData3, pThis->key2);
        pThis->key3IP3 = (pThis->IP3isMultiple && !pThis->key3IsDoubleKey) ? 0 : _SWCSearchDB_GetIPWDistance(pThis, pThis->ipData3, pThis->key3);
        pThis->IP3isPenUp = (ET9BOOL)((pThis->forward) ? ((pThis->ipData3->m_IPType == PenUp) || (pThis->ipData3->m_IPType == SoftUp)) : (pThis->ipData3->m_IPType == PenDown));
    }
    else
    {
        pThis->ipData3 = NULL;
        pThis->key1IP3 = pThis->key2IP3 = pThis->key3IP3 = 0;
        pThis->IP3isPenUp = _FALSE;
        pThis->IP3isPathDivision = pThis->IP3isMultiple = pThis->IP3isArtificial = _TRUE;
    }
    /* SavedCodeSegments/269 - PERFORM_FUTURE_MATCH_CHECK code */
}       /* SetKeyDistancesFromKeyRepeats() */


ET9BOOL ET9FARCALL _SWCSearchDB_checkTranspositions(_SWCSearchDB *pThis, ET9BOOL *swappedNext, ET9BOOL *swappedPrev, SBYTE2 keyLimit)
{
    SBYTE2 indexM2, indexM1, indexC, indexP1, indexP2;
    indexM2 = pThis->keyIndex - 3;
    indexM1 = pThis->keyIndex - 2;
    indexC = pThis->keyIndex - 1;
    indexP1 = pThis->keyIndex;
    indexP2 = pThis->keyIndex + 1;
    *swappedNext = *swappedPrev = _FALSE;
    if (pThis->transposeCount > 0)
    {
        if ((indexM2 >= 0) && (pThis->keyFlags[indexM2] == TRANSPOSED_NEXT))
        {
            pThis->swapPos = indexM2;     /* Original position of key causing transposition */
            pThis->omitPos = indexM1;     /* Current position of key causing transposition */
            *swappedNext = _TRUE;
        }
        else if ((indexM1 >= 0) && (pThis->keyFlags[indexM1] == TRANSPOSED_NEXT))
        {
            pThis->swapPos = indexM1;     /* Original position of key causing transposition */
            pThis->omitPos = indexC;      /* Current position of key causing transposition */
            *swappedNext = _TRUE;
        }
        else if ((indexM2 > 0) && ((pThis->keyFlags[indexM1] == TRANSPOSED_PREV) || (pThis->keyFlags[indexM1] == TRANSPOSED_PREV_ONLY)))
        {
            pThis->swapPos = indexM1;     /* Original position of key causing transposition */
            pThis->omitPos = indexM2;     /* Current position of key causing transposition */
            *swappedPrev = _TRUE;
        }
        else if ((indexM1 > 0) && ((pThis->keyFlags[indexC] == TRANSPOSED_PREV) || (pThis->keyFlags[indexC] == TRANSPOSED_PREV_ONLY)))
        {
            pThis->swapPos = indexC;      /* Original position of key causing transposition */
            pThis->omitPos = indexM1;     /* Current position of key causing transposition */
            *swappedPrev = _TRUE;
        }
        else if ((indexC >= 0) && (pThis->keyFlags[indexC] == TRANSPOSED_NEXT))
        {
            pThis->swapPos = indexC;       /* Original position of key causing transposition */
            pThis->omitPos = indexP1;      /* Current position of key causing transposition */
            *swappedNext = _TRUE;
        }
        else if ((indexP1 < keyLimit) && ((pThis->keyFlags[indexP1] == TRANSPOSED_PREV) || (pThis->keyFlags[indexP1] == TRANSPOSED_PREV_ONLY)))
        {
            pThis->swapPos = indexP1;     /* Original position of key causing transposition */
            pThis->omitPos = indexC;      /* Current position of key causing transposition */
            *swappedPrev = _TRUE;
        }
        else if ((indexP2 < keyLimit) && (pThis->keyFlags[indexP1] == TRANSPOSED_NEXT))        /* See if following key already transposed */
        {
            pThis->swapPos = indexP1;     /* Original position of key causing transposition */
            pThis->omitPos = indexP2;     /* Current position of key causing transposition */
            *swappedNext = _TRUE;
        }
    }
    return(*swappedNext || *swappedPrev);
}

CPOS ET9FARCALL _SWCSearchDB_findTransposedCharOffset(_SWCSearchDB *pThis, CPOS keyPos, CPOS keyLimit)
{
    CPOS charOffset = 0;
    if (pThis->transposeCount > 0)
    {
        if ((keyPos >= 1) && ((pThis->keyFlags[keyPos - 1] == TRANSPOSED_NEXT) || (pThis->keyFlags[keyPos] == TRANSPOSED_PREV) || (pThis->keyFlags[keyPos] == TRANSPOSED_PREV_ONLY)))
        {
            charOffset = -(pThis->m_keyRepeats[keyPos - 1] + 1);
        }
        else if ((keyPos < (keyLimit - 1)) &&
                 ((pThis->keyFlags[keyPos] == TRANSPOSED_NEXT) || (pThis->keyFlags[keyPos + 1] == TRANSPOSED_PREV) || (pThis->keyFlags[keyPos + 1] == TRANSPOSED_PREV_ONLY)))
        {
            charOffset = pThis->m_keyRepeats[keyPos] + 1;
        }
    }
    return(charOffset);
}

void ET9FARCALL _SWCSearchDB_setIPVars(_SWCSearchDB *pThis)
{
    pThis->ipData = pThis->m_aIPTable[pThis->ipIndex];       /* Same for both cases */
    if (pThis->forward)
    {
        if (pThis->ipIndex > 0)
            pThis->seg1Data = pThis->ipData;
        else
            pThis->seg1Data = NULL;
        if ((pThis->ipIndex + 1) < pThis->m_wIPTableCount)
        {
            pThis->seg2Data = pThis->m_aIPTable[pThis->ipIndex + 1];
            if ((pThis->ipIndex + 2) < pThis->m_wIPTableCount)
                pThis->seg3Data = pThis->m_aIPTable[pThis->ipIndex + 2];
            else
                pThis->seg3Data = NULL;
        }
        else
            pThis->seg2Data = pThis->seg3Data = NULL;
    }
    else    /* Suffixes */
    {
        if (pThis->ipIndex > 0)
            pThis->seg1Data = pThis->m_aIPTable[pThis->ipIndex - 1];
        else
            pThis->seg1Data = NULL;
        if (pThis->ipIndex < (pThis->m_wIPTableCount - 1))
        {
            pThis->seg2Data = pThis->ipData;
            if ((pThis->ipIndex + 1) < (pThis->m_wIPTableCount - 1))
                pThis->seg3Data = pThis->m_aIPTable[pThis->ipIndex + 1];
            else
                pThis->seg3Data = NULL;
        }
        else
            pThis->seg2Data = pThis->seg3Data = NULL;
    }
}

void ET9FARCALL _SWCSearchDB_RestoreEnvironmentFromKeyRepeats(_SWCSearchDB *pThis, SBYTE2 omittedCount, SBYTE2 *matchPosIndex, float *skipPenalty, SBYTE2 *skippedIPs)
{
    SBYTE2 i;
    /* Restore environment to state when preceding key was first processed */
    if (pThis->keyIndex > 0)
    {
        while ((pThis->keyIndex > 0) &&
               (_SWCSearchDB_InvalidPosIndex(pThis, matchPosIndex[pThis->keyIndex - 1]) ||       /* Or if the preceding match location is not available */
                _SWCSearchDB_InvalidPosIndex(pThis, pThis->matchLocExitIndex[pThis->keyIndex - 1])
                ) )
            pThis->keyIndex--;                                                     /*   May have to back up more than once (e.g. IEEE, delete "p" in "deepest", etc.) */
    }
    if (omittedCount > 0)
    {
        SBYTE2 j;
        for (j = pThis->omitPos; j < pThis->keySeqLength; j++)   /* Over-write omitted key */
        {
            pThis->keyFlags[j] = pThis->keyFlags[j + 1];
            pThis->ipIndexKey[j] = pThis->ipIndexKey[j + 1];
        }
    }
    _SWCSearchDB_SetDoubleIndicesFromKeyRepeats(pThis, pThis->m_keyRepeats, pThis->keySeqLength);
    _SWCSearchDB_ResetDoubleIndices(pThis, pThis->keyIndex);
    if (pThis->keyIndex > 0)
    {
        pThis->lastKey = pThis->keys[pThis->keyIndex - 1];
        pThis->lastMatchKeyPosIndex = matchPosIndex[pThis->keyIndex - 1];
        pThis->lastMatchKeyLocIndex = pThis->matchLocExitIndex[pThis->keyIndex - 1];
        pThis->lastMatchKeyPos = _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->lastMatchKeyPosIndex);
        pThis->lastMatchKeyLoc = _SWCSearchDB_GetZ1FixedPoint(pThis, pThis->lastMatchKeyLocIndex);
        pThis->altLastMatchKeyPosIndex = pThis->altLastMatchKeyLocIndex = 0;          /* ??? For now, can't identify alternate match location */
        pThis->altLastMatchKeyLoc = pThis->altLastMatchKeyPos = pThis->lastMatchKeyLoc;
    }
    else
    {
        pThis->lastKey = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);       /* Init to invalid (nonexistant) key */
    }
    /* Need to re-calculate skipPenalty and skippedIPs as sums of previous values when restoring earlier matching environment */
    *skipPenalty = 0.0;
    *skippedIPs = 0;
    for (i = 0; i < pThis->keyIndex; i++)
    {
        *skipPenalty = (SBYTE2)(*skipPenalty + pThis->skipPenaltyKey[i]);
        *skippedIPs = (SBYTE2)(*skippedIPs + pThis->skippedIPsCount[i]);
    }
    for (i = pThis->keyIndex; i < pThis->keySeqLength; i++)
    {
        pThis->skipPenaltyKey[i] = 0;
        pThis->skippedIPsCount[i] = 0;
        pThis->hasSkippedIPs[i] = _FALSE;
        pThis->ipIndexKey[i] = -1;
    }
    if (pThis->keyIndex > 0)
    {
        SBYTE2 lastMatchedKey = pThis->keyIndex - 1;
        while ((lastMatchedKey > 0) && (pThis->ipIndexKey[lastMatchedKey] < 0))    /* Skip back (if needed) to valid index value */
            lastMatchedKey--;
        if (lastMatchedKey > 0)
            pThis->ipIndex = pThis->ipIndexKey[lastMatchedKey] + 1;       /* Set ipIndex to one greater than last matched IP */
        else
            pThis->ipIndex = 1;
        if (pThis->ipIndex >= pThis->m_wIPTableCount)
            pThis->ipIndex = pThis->m_wIPTableCount - 1;
    }
    else
        pThis->ipIndex = 0;

    _SWCSearchDB_setIPVars(pThis);
    pThis->advanceIP = _FALSE;
}

/* Record position of omission, adjusting for previous omission (if any) so position */
/*   in original word is recorded.  Return number of keys omitted if ommission allowed, _FALSE otherwise. */
SBYTE2 ET9FARCALL _SWCSearchDB_RecordKeyOmissionFromKeyRepeats(_SWCSearchDB *pThis, SBYTE2 omitPosRelative, SBYTE2 omitPosActual)
{
    SBYTE2 omitted = 1;

    SBYTE2 recordPosition = pThis->omissionCount;

    if (pThis->omissionCount < pThis->maxKeyErrorCountActual)
    {
        if (pThis->omissionCount > 0)     /* Quit if we are now trying to delete an earlier key from the root */
        {       /* Compare to key previously omitted from root */
            if ((omitPosRelative < pThis->omitKeys[pThis->omissionCount - 1]) || (omitPosActual < pThis->omitKeysActual[pThis->omissionCount - 1]))
            {
                omitted = 0;
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    if (pThis->thisWord != NULL)
                    {
                        Log(SWLogger_DEBUG,TEXT(" Word %s FAILED due to deleting earlier key!\r\n"), pThis->thisWord->externalText);
                    }
                }
#endif
            }
        }
    }
    else
        omitted = 0;
    if ((omitted > 0) && (pThis->omissionCount < OMIT_KEYS_MAX) && (recordPosition < OMIT_KEYS_MAX) && (pThis->keySeqLength < DEFAULT_WORD_SIZE))
    {
        if ((omitPosRelative < (pThis->keySeqLength - 1)) && (pThis->m_keyRepeats[omitPosRelative] > 0))
            omitted = pThis->m_keyRepeats[omitPosRelative] + 1;
        if (recordPosition < pThis->omissionCount)
        {
            SBYTE2 i;
            for (i = pThis->omissionCount; i > recordPosition; i--)
            {
                pThis->omitKeys[i] = pThis->omitKeys[i - 1] - 1;            /*lint !e817 */
                pThis->omitKeysActual[i] = pThis->omitKeysActual[i - 1];          /*lint !e817 */
            }
        }
        pThis->omitKeys[recordPosition] = (BYTE1)omitPosRelative;      /* Removed " + recordPosition" */
        pThis->omitCounts[recordPosition] = (BYTE1)omitted;
        pThis->omitKeysActual[recordPosition] = (BYTE1)(omitPosActual + recordPosition);
        pThis->lastOmittedKey = omitPosActual;
        if (!DebugAssert(omitPosRelative >= 0))
            omitPosRelative = 0;
        omitted = pThis->m_keyRepeats[omitPosRelative] + 1;
        pThis->omissionCount++;
        pThis->omitCount = (SBYTE2)(pThis->omitCount + omitted);
        {
            SBYTE2 i;
            for (i = omitPosRelative; i < pThis->keySeqLength; i++)   /* Over-write omitted key */
            {
                pThis->keys[i] = pThis->keys[i + 1];
                pThis->m_keyRepeats[i] = pThis->m_keyRepeats[i + 1];
            }
        }
    }
    else
    {
       _SWCSearchDB_FailCandidate(pThis);
    }
    if (omitted > 0)
    {
        pThis->keyLimit--;            /* Reduce keyLimit and keySeqLength since omitted key(s) was(were) deleted */
        if ((pThis->omitPos < pThis->keyLimitSuffix) || (pThis->swapPos < pThis->keyLimitSuffix))
            pThis->keyLimitSuffix--;
        pThis->keySeqLength--;
        pThis->lastChangeIndex = pThis->omitPos;       /* Back-up keyIndex to that of key to omit */
        if (pThis->omitPos > 1)
        {
            pThis->keyIndex = pThis->omitPos - 1;             /* Re-process key position preceding transposed or omitted key since now have different "key2" */
            pThis->keyIndexM1 = pThis->keyIndex - 1;
        }
        else
            pThis->keyIndex = pThis->keyIndexM1 = 0;
        pThis->finalKey = _FALSE;           /* Even if we were on final key, we still haven't matched it */
    }
    return(omitted);
}   /* RecordKeyOmissionFromKeyRepeats() */

/*============================================================================= */
/* Function:    _SWCSearchDB_CheckTransposeOmitKey() */
/* Parameters:  See below! */
/* Description: Determine whether the current key (which does not match at the */
/*              current point in the input path) can match on the path segment */
/*              preceding the previously matched key, or following the point where */
/*              the following key can match, and if so, transpose the appropriate */
/*              keys in the key sequence and record the alteration.  Otherwise, */
/*              omit the current key from the key sequence and assess a corresponding */
/*              penalty. */
/*============================================================================= */
SBYTE2 ET9FARCALL _SWCSearchDB_CheckTransposeOmitKey(_SWCSearchDB *pThis, SBYTE2 *matchPosIndex, SBYTE2 fixedLimit, float *skipPenalty, SBYTE2 *skippedIPs)
{
    ET9BOOL    transposeOK = _FALSE, swapPrevOK = _FALSE, swapNextOK = _FALSE, omitKeyOK = _FALSE, transposed = _FALSE;
    ET9BOOL    keyAlreadyTransposed = _FALSE, key2AlreadyTransposed = _FALSE, swappedPrev = _FALSE, swappedNext = _FALSE;
    SBYTE2  omitted = 0;
    SBYTE2  retVal = 0;

#if DEBUG_SHOW_MATCH_TRACE
    if (debugThis)
        pThis->bBreakHere = _TRUE;
#endif
    retVal = NO_CHANGE;
    /* If no more errors permitted, then it's time to fail the current candidate */
    if ((pThis->omissionCount + pThis->transposeCount) >= pThis->maxKeyErrorCountActual)
    {
        _SWCSearchDB_FailCandidate(pThis);
        return(NO_CHANGE);
    }
    pThis->omitPos = pThis->keyIndex - 1;     /* Default omit position is that of current key (if */
                                /*   attempt to transpose below fails) */
    pThis->swapPos = -1;               /* Init to invalid value to confirm proper case detected */
    /* If preceding key was already transposed (...ABC... => ...BAC...) , then it is */
    /* time to simply omit key A (rather than transpose to BCA).  If we haven't transposed */
    /* yet, then try transposing now */
    if (pThis->transpositionLevel > NO_TRANSPOSITIONS)
    {
        /* Check whether any earlier transposition should simply be classified as an omission */
        /* Set flag if current or previous key was the result of a previous transposition */
        keyAlreadyTransposed = _SWCSearchDB_checkTranspositions(pThis, &swappedNext, &swappedPrev, pThis->keyLimit);
        /* set matchKey = OMIT_TRANSPOSED_KEY in ALL keyAlreadyTransposed cases... */
        if (keyAlreadyTransposed)
            pThis->matchKey = OMIT_TRANSPOSED_KEY;
        /* If matchKey is set to OMIT_TRANSPOSED_KEY, we should have found a transposition.  Quit now if none found. */
        else if (pThis->matchKey == OMIT_TRANSPOSED_KEY)
        {
            return(NO_CHANGE);
        }
        key2AlreadyTransposed = (ET9BOOL)((((pThis->keyIndex + 1) < pThis->keyLimit) && ((pThis->keyFlags[pThis->keyIndex + 1] == TRANSPOSED_PREV) || (pThis->keyFlags[pThis->keyIndex + 1] == TRANSPOSED_PREV_ONLY))) ||
                                    ((pThis->keyIndex < pThis->keyLimit) && (pThis->keyFlags[pThis->keyIndex] != NO_CHANGE) && (pThis->keyFlags[pThis->keyIndex] != OMIT_KEY_LATER)));
        /* Prior to transposing based on encountering a potential out-of-order match with the */
        /* following key, first confirm that there is not a reasonable in-order upcoming */
        /* match sequence. */
        if (!keyAlreadyTransposed && (pThis->matchKey >= NEXT_KEY_IP_MATCH) && (pThis->matchKey <= NEXT_KEY_SEGMENT_MATCH))   /* {HERE} (ipIndex < pThis->m_wIPTableCount (< pThis->m_wIPTableCount-1)?) */
        {
            /* First see if current key1 is NOT final key, and and current IP is PenUp IP (or IP preceding PenUp), then just omit current key */
            if (pThis->forward && (pThis->keysRemaining > 1) &&
                ((pThis->IP1isPenUp && (((pThis->keysRemaining == 2) && pThis->key2IP1) || ((pThis->keysRemaining == 3) && pThis->key3IP1))) ||
                 (pThis->IP2isPenUp && (pThis->keysRemaining == 3) && pThis->key2IP1 && !pThis->key2Seg2 && !pThis->key1Seg2 && pThis->key3IP2)))
            {
                pThis->matchKey = OMIT_CURRENT_KEY;
            }
        }
        if (pThis->matchKey == OMIT_TRANSPOSED_KEY)
        {
            if (keyAlreadyTransposed)
            {
                omitKeyOK = (ET9BOOL)(pThis->omitPos > 0);
                if (omitKeyOK && (pThis->swapPos >= 0))
                {
                    if ((pThis->transposeCount <= 0) || (pThis->keyFlags[pThis->swapPos] == NO_CHANGE))
                    {
                        _SWCSearchDB_FailCandidate(pThis);
                        return(NO_CHANGE);
                    }
                    pThis->transposeCount--;
                    pThis->keyFlags[pThis->swapPos] = NO_CHANGE;
                    if ((pThis->vowelTransposeCount > 0) && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos], _TRUE) &&
                        ((swappedNext && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos + 1], _TRUE)) ||
                         (swappedPrev && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos - 1], _TRUE))))
                        pThis->vowelTransposeCount--;
                }
            }
            else
            {

                Log(SWLogger_INFO, SWTEXT("Swype Event: %d \n"), 420)
                pThis->matchKey = OMIT_CURRENT_KEY;
            }
        }
    }
    else        /* If no transpositions permitted, then just omit current key */
        pThis->matchKey = OMIT_CURRENT_KEY;
    if (pThis->matchKey == OMIT_CURRENT_KEY)
    {
        pThis->omitPos = pThis->swapPos = pThis->keyIndex - 1;       /* Position of current key */
        omitKeyOK = (ET9BOOL)(pThis->omitPos > 0);
    }
    if ((pThis->transpositionLevel > NO_TRANSPOSITIONS) && (pThis->matchKey != OMIT_TRANSPOSED_KEY) && !omitted && (pThis->keyIndex > 1))
    {
        /* TODO(CAK): Eliminate this step or confirm that it is useful enough to keep */
        /* If only preceding key transposed, try following key (if not already hitting end of word).  Transposition attempt may fail */
        /*   since there is minimal pre-testing for consistency with path and previously matched keys */
        if ((pThis->keyFlags[pThis->keyIndex] == TRANSPOSED_PREV) && (pThis->keyIndex < (pThis->keySeqLength - 1)))
        {
            /* Restore order of keys from previous transposition, then try transposing with following key */
            BYTE1 key_1 = pThis->keys[pThis->keyIndex - 1];           /* restore previously swapped keys */
            BYTE1 keyRepeat1 = pThis->m_keyRepeats[pThis->keyIndex - 1];
            pThis->keys[pThis->keyIndex - 1] = pThis->keys[pThis->keyIndex];
            pThis->keys[pThis->keyIndex] = key_1;
            pThis->m_keyRepeats[pThis->keyIndex - 1] = pThis->m_keyRepeats[pThis->keyIndex];
            pThis->m_keyRepeats[pThis->keyIndex] = keyRepeat1;

            pThis->keyFlags[pThis->keyIndex] = (BYTE1)(retVal = TRANSPOSED_NEXT);
            pThis->keyIndex++;                             /* Advance to position of following to-be-swapped-below key */
            pThis->keyIndexM1 = pThis->keyIndex - 1;
            pThis->lastChangeIndex = pThis->keyIndex;
            pThis->matchKey = CURRENT_KEY_TRANSPOSED;      /* Set matchKey so proper skipping penalty assessed */
            pThis->finalKey = _FALSE;                       /* Even if we were on final key, we still haven't matched it */
            transposeOK = swapNextOK = _TRUE;        /* Swap following key below */
        }
        else if (!keyAlreadyTransposed && ((pThis->omissionCount + pThis->transposeCount) < pThis->maxKeyErrorCountActual) &&
                    _SWCSearchDB_SwapKeysOKFromKeyRepeats(pThis, (pThis->keyIndex - 1), pThis->keySeqLength, &swapPrevOK, &swapNextOK, &omitKeyOK))
        {
            /* Determine whether current key (keys[pThis->keyIndex - 1]) can be swapped with preceding or following key */
            SBYTE2  prevMatchPosIndex = 0;
            BYTE1   key_1 = pThis->keys[pThis->keyIndex - 1];
            SWCIPTableRow *ipTest, *segTest;
            SBYTE2  ipCheck, segCheck;
            ET9BOOL    ipCheckOK, segCheckOK;
            BYTE2   prevMatchIP = 0, prevMatchSeg = 0, prevMatchScore = 0;
            SBYTE2  begPos, endPos;
            SBYTE2  ipTestPosIndex, prevMatchLocIndex;
            _SWPoint prevMatchLoc, prevMatchPos;
            pThis->swapPos = pThis->omitPos = pThis->keyIndex - 1;   /* Set in case transposition attempt fails */
            if (swapPrevOK)
            {
                if ((pThis->keyIndex >= 3) && (pThis->ipIndexKey[pThis->keyIndex - 3] >= 0))      /* Must be at least at 3rd key to swap with preceding (can't swap 1st key) */
                {
                    ipCheck = pThis->ipIndexKey[pThis->keyIndex - 3];
                    begPos = matchPosIndex[pThis->keyIndex - 3];
                    endPos = matchPosIndex[pThis->keyIndex - 2];
                    if (pThis->forward)
                    {
                        ipTestPosIndex = 0;
                        segCheck = ipCheck + 1;
                        ipCheckOK = (ET9BOOL)((ipTestPosIndex <= endPos) && (ipCheck < pThis->m_wIPTableCount));
                        segCheckOK = (ET9BOOL)(segCheck < pThis->m_wIPTableCount);
                    }
                    else
                    {
                        ipTestPosIndex = endPos + 1;        /* Init so loop is entered; */
                        segCheck = ipCheck;
                        ipCheckOK = (ET9BOOL)((ipTestPosIndex >= endPos) && (ipCheck < pThis->m_wIPTableCount));
                        segCheckOK = (ET9BOOL)(segCheck < pThis->m_wIPTableCount);
                    }
                    while (!prevMatchPosIndex && ipCheckOK)
                    {
                        ipTest = pThis->m_aIPTable[ipCheck];
                        ipTestPosIndex = ipTest->m_IPPosIndex;
                        prevMatchIP = _SWCSearchDB_GetIPWDistance(pThis, ipTest, key_1);
                        if (prevMatchIP)
                        {
                            prevMatchPosIndex = ipTestPosIndex;
                            if (_SWCSearchDB_PointsInSequence(pThis, prevMatchPosIndex, begPos) || _SWCSearchDB_PointsInSequence(pThis, endPos, prevMatchPosIndex))
                            {
                                prevMatchPosIndex = 0;
                                prevMatchIP = 0;        /* Clear so we know below whether prevMatch was to an IP or not */
                            }
                            else
                                prevMatchScore = prevMatchIP;
                        }
                        if (!prevMatchPosIndex && segCheckOK)
                        {
                            segTest = pThis->m_aIPTable[segCheck];
                            prevMatchSeg = _SWCSearchDB_GetSegmentWDistance(pThis, segTest, key_1, fixedLimit);
                            if (prevMatchSeg)
                            {
                                prevMatchPosIndex = _SWCSearchDB_GetSegmentMatchPos(pThis, segTest, key_1, &prevMatchPos, &prevMatchLoc, &prevMatchLocIndex);
                                if (_SWCSearchDB_PointsInSequence(pThis, prevMatchPosIndex, begPos) || _SWCSearchDB_PointsInSequence(pThis, endPos, prevMatchPosIndex))
                                    prevMatchPosIndex = 0;
                                else
                                    prevMatchScore = prevMatchSeg;
                            }
                        }
                        ipCheck++;
                        ipCheckOK = (ET9BOOL)(ipCheck < pThis->m_wIPTableCount);
                        segCheck++;
                        segCheckOK = (ET9BOOL)(segCheck < pThis->m_wIPTableCount);
                        if (ipCheckOK)
                        {
                            ipCheckOK = _SWCSearchDB_PointsInSequenceOrIdentical(pThis, ipTestPosIndex, endPos);
                        }
                    }
                }
                if (!prevMatchPosIndex)     /* If no potential swap found earlier on the input path */
                    swapPrevOK = _FALSE;
            }
            /* SavedCodeSegments/SearchDB.cpp/18 (start of code to test for valid TRANSPOSE_NEXT case) */
            if (swapPrevOK)     /* If we found a potential swap earlier on the input path, swap with preceding key */
            {
                /* test swapNextOK, use keyIP2, etc., then compare to prevMatchScore.  See if prevMatchPosIndex already matched to previous key */
                /* If swapNextOK is also true, determine which transposition is more likely */
                if (swapNextOK)
                {
                    /* First determine if prevMatchPosIndex has already been matched to a preceding key */
                    ET9BOOL alreadyMatchedPrev = _FALSE;
                    SBYTE2 matchedKeyIndex = -1;
                    SBYTE2 i;
                    for (i = 0; (i < (pThis->keyIndex - 1)) && !alreadyMatchedPrev; i++)
                    {
                        if (prevMatchPosIndex == matchPosIndex[i])
                        {
                            alreadyMatchedPrev = _TRUE;
                            matchedKeyIndex = i;
                        }
                    }
                    /* Only consider swapPrev if swapped key would have a better score */
                    if (alreadyMatchedPrev)
                        swapPrevOK = (ET9BOOL)(pThis->rawScoreKey[matchedKeyIndex] > prevMatchScore);       /*lint !e676 */
                    if (swapPrevOK)     /* If previous swap not yet disqualified, compare to possible next swap */
                    {
                        BYTE2 nextMatchScore = 0;
                        ET9BOOL  noSkipNextMatch = _FALSE;      /* Flag if we can match next without skipping an IP */
                        ET9BOOL  avoidSkipPrevMatch = (ET9BOOL)(!alreadyMatchedPrev && prevMatchIP);    /* Flag if matching prev matches an otherwise-skipped IP */
                        ET9BOOL  avoidSkipNextMatch = _FALSE;
                        if (pThis->key2IP1 && (pThis->matchKey == NEXT_KEY_IP_MATCH))
                        {
                            if (pThis->key1IP2 || pThis->key1Seg2)
                            {
                                nextMatchScore = pThis->key2IP1;
                                noSkipNextMatch = _TRUE;
                                avoidSkipNextMatch = (ET9BOOL)(pThis->key1IP2 && !pThis->key3IP2);
                            }
                        }
                        else if (pThis->key2Seg1 && (pThis->matchKey == NEXT_KEY_SEGMENT_MATCH))
                        {
                            if ((pThis->key1Seg1 && _SWCSearchDB_PointsInSequenceOrIdentical(pThis, pThis->key1Seg1PosIndex, pThis->key2Seg1PosIndex)) || pThis->key1IP1)
                            {
                                nextMatchScore = pThis->key2Seg1;
                                noSkipNextMatch = _TRUE;
                            }
                            else if (pThis->key1IP2 || pThis->key1Seg2)
                            {
                                nextMatchScore = pThis->key2Seg1;
                            }
                        }
                        if (nextMatchScore > 0)
                        {
                            if (!avoidSkipPrevMatch && avoidSkipNextMatch)          /* neutral - positive: Raw scores determine choice */
                                swapNextOK = (ET9BOOL)(nextMatchScore < (3 * prevMatchScore));
                            else if (!avoidSkipPrevMatch && noSkipNextMatch)        /* neutral - neutral: Raw scores determine choice */
                                swapNextOK = (ET9BOOL)(nextMatchScore < prevMatchScore);
                            else if (nextMatchScore < prevMatchScore)               /* Next has better score... */
                            {
                                if (avoidSkipPrevMatch && !noSkipNextMatch)         /* positive - negative: Go with prev unless very large score difference */
                                    swapNextOK = (ET9BOOL)(prevMatchScore > (3 * nextMatchScore));
                                else if (avoidSkipPrevMatch)  /* implicitly, && noSkipNextMatch  (positive - neutral) */
                                    swapNextOK = (ET9BOOL)(prevMatchScore > (2 * nextMatchScore));
                                else                          /* implicitly, !avoidSkipPrevMatch && !noSkipNextMatch  (neutral - negative) */
                                    swapNextOK = (ET9BOOL)((2 * prevMatchScore) > (3 * nextMatchScore));
                            }
                            else                                                    /* Prev has better score... */
                            {
                                if (avoidSkipPrevMatch)         /* positive - negative or positive - neutral: Go with prev */
                                    swapNextOK = _FALSE;
                                else                            /* implicitly, !avoidSkipPrevMatch && !noSkipNextMatch  (neutral - negative) */
                                    swapNextOK = (ET9BOOL)(prevMatchScore > (2 * nextMatchScore));
                            }
                        }
                        else
                            swapNextOK = _FALSE;
                    }
                    if (swapNextOK)
                        swapPrevOK = _FALSE;
                }
            }
            if (swapPrevOK)     /* If we found a potential swap earlier on the input path, swap with preceding key */
            {
                transposeOK = _TRUE;
                pThis->transposeCount++;
                if (_SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->keyIndex - 1], _TRUE) && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->keyIndex - 2], _TRUE))
                    pThis->vowelTransposeCount++;
                if (swapNextOK)
                    pThis->keyFlags[pThis->keyIndex - 1] = (BYTE1)(retVal = TRANSPOSED_PREV);
                else
                    pThis->keyFlags[pThis->keyIndex - 1] = (BYTE1)(retVal = TRANSPOSED_PREV_ONLY);
                pThis->lastChangeIndex = pThis->keyIndex - 1;
                pThis->keyIndex--;
            }
            else if (swapNextOK)        /* Check for key2AlreadyTransposed, if true, just return */
            {
                if (!key2AlreadyTransposed)
                {
                    transposeOK = _TRUE;
                    pThis->transposeCount++;
                    if (_SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->keyIndex - 1], _TRUE) && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->keyIndex], _TRUE))
                        pThis->vowelTransposeCount++;
                    pThis->keyFlags[pThis->keyIndex - 1] = (BYTE1)(retVal = TRANSPOSED_NEXT);
                    pThis->lastChangeIndex = pThis->keyIndex;
                }
                else
                {
                    return(NO_CHANGE);
                }
            }
        }
        else if (omitKeyOK)
        {
            /* SwapKeysOK() returns false (i.e. no valid transposition) but omitKey is true, set omitPos, swapPos, etc. */
            pThis->omitPos = pThis->swapPos = pThis->keyIndex - 1;       /* Position of current key */
            omitKeyOK = (ET9BOOL)(pThis->omitPos > 0);
            if (omitKeyOK)
                pThis->matchKey = OMIT_CURRENT_KEY;        /* Process simply as omission of current key */
            else
                return(NO_CHANGE);
        }
        if (transposeOK)
        {
            /* Switch order of keys to test for transposition */
            BYTE1 key_1 = pThis->keys[pThis->keyIndex - 1];
            BYTE1 keyRepeat1 = pThis->m_keyRepeats[pThis->keyIndex - 1];
            pThis->keys[pThis->keyIndex - 1] = pThis->keys[pThis->keyIndex];
            pThis->keys[pThis->keyIndex] = key_1;
            pThis->m_keyRepeats[pThis->keyIndex - 1] = pThis->m_keyRepeats[pThis->keyIndex];
            pThis->m_keyRepeats[pThis->keyIndex] = keyRepeat1;
            pThis->matchKey = CURRENT_KEY_TRANSPOSED;      /* Set matchKey so proper skipping penalty assessed */
            pThis->finalKey = _FALSE;           /* Even if we were on final key, we still haven't matched it */
            if (pThis->keyIndex > 2)
            {
                pThis->keyIndex -= 2;              /* Re-process key position preceding transposed or omitted key since now have different "key2" */
                pThis->keyIndexM1 = pThis->keyIndex - 1;
            }
            else
                pThis->keyIndex = pThis->keyIndexM1 = 0;
            transposed = _TRUE;
        }
        else    /* Neither key can be matched following the other, so omit current key */
        {
            if (keyAlreadyTransposed)       /* If omitting, omit key that was cause of previous (unsuccessful) transposition */
            {
                /* Set keyIndex to (index+1) of of key that triggered transposition (since */
                /*   keyIndex is decremented below) */
                if (pThis->transposeCount <= 0)
                {
                    _SWCSearchDB_FailCandidate(pThis);
                    return(NO_CHANGE);
                }
                pThis->transposeCount--;               /* Eliminating previous transposition */
                if (pThis->keyFlags[pThis->swapPos] == NO_CHANGE)
                {
                    _SWCSearchDB_FailCandidate(pThis);
                    return(NO_CHANGE);
                }
                pThis->keyFlags[pThis->swapPos] = NO_CHANGE;  /* Key now omitted, not transposed */
                if ((pThis->vowelTransposeCount > 0) && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos], _TRUE) &&
                    ((swappedNext && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos + 1], _TRUE)) ||
                     (swappedPrev && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos - 1], _TRUE))))
                    pThis->vowelTransposeCount--;
            }
            omitKeyOK = (ET9BOOL)(omitKeyOK && (pThis->omitPos > 0));
            if (omitKeyOK)
            {
                /* Record position of omission, adjusting for previous omission (if any) so position */
                /*   in original word is recorded */
                omitted = _SWCSearchDB_RecordKeyOmissionFromKeyRepeats(pThis, pThis->omitPos, pThis->swapPos);
                if (omitted > 0)
                {
                    pThis->matchKey = OMIT_CURRENT_KEY;        /* Set matchKey so proper skipping penalty assessed */
                    retVal = OMITTED;       /* Set return flag to reflect omitted key */
                }
                else
                    omitKeyOK = _FALSE;
            }
            if (!omitKeyOK)
            {
                _SWCSearchDB_FailCandidate(pThis);
                return(NO_CHANGE);
            }
        }
    }
    if (((pThis->matchKey == OMIT_CURRENT_KEY) || (pThis->matchKey == OMIT_TRANSPOSED_KEY)) && omitKeyOK && !omitted)
    {
        /* Record position of omission, adjusting for previous omission (if any) so position */
        /*   in original word is recorded */
        omitted = _SWCSearchDB_RecordKeyOmissionFromKeyRepeats(pThis, pThis->omitPos, pThis->swapPos);
        if (omitted > 0)
        {
            retVal = OMITTED;
        }
        else
            return(NO_CHANGE);
    }
    if ((pThis->omissionCount + pThis->transposeCount) > pThis->maxKeyErrorCountActual)
    {
#if DEBUG_LOG_MATCH_TRACE
        if (debugThis)
        {
            if (pThis->thisWord != NULL)
            {
                Log(SWLogger_DEBUG, TEXT(" Word %s FAILED due exceeding maxKeyErrorCountActual (%d)!\r\n"), pThis->thisWord->externalText, pThis->maxKeyErrorCountActual);
                Log(SWLogger_DEBUG, TEXT(" Omitted: %d   Transposed (vowels): %d (%d)\n"), pThis->omitCount, pThis->transposeCount, pThis->vowelTransposeCount);
            }
        }
#endif
        _SWCSearchDB_FailCandidate(pThis);
        return(NO_CHANGE);
    }
    else if ((omitted || transposed) && (retVal != NO_CHANGE))
    {
        /* Restore environment to state when preceding key was first processed */
        _SWCSearchDB_RestoreEnvironmentFromKeyRepeats(pThis, omitted, matchPosIndex, skipPenalty, skippedIPs);
        /* If dualMatch was previously set, reset it now since the environment has changed, and the final key will be to be re-scored */
        if (pThis->dualMatchSet)
        {
            pThis->dualMatch = NO_PATTERN_MATCH;
            pThis->dualMatchSet = _FALSE;
        }
        return(retVal);
    }
    return(NO_CHANGE);
}   /* _SWCSearchDB_CheckTransposeOmitKey() */

static ET9INLINE ET9BOOL _SWCSearchDB_isDoubleGestureMatch(SBYTE2 matchKeyType)
{
    if (matchKeyType == DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH)
        return(_TRUE);
    return(_FALSE);
}


/* SavedCodeSegments/244 - TRIAGE_APPROACH */

/*============================================================================= */
/* Function:    _SWCSearchDB_ScoreWordFromKeyRepeats() */
/* Parameters:  Word *dbWord - Pointer to Word object from MGD database to be scored against */
/*              the current IPTable */
/* Description: Score *dbWord against the current input path, saving the */
/*              scoring results within the *dbWord object.itself, and determine */
/*              whether the word is a possible match with the input path. */
/* Returns:     1 - Word examined (scored) and found to ba a valid candidate */
/*              0 - Word NOT scored (filtered out according to current criteria) */
/*             -1 - Word examined (scored) and found NOT to ba a valid candidate */
/*============================================================================= */

int ET9FARCALL _SWCSearchDB_ScoreWordFromKeyRepeats(_SWCSearchDB *pThis, _SWWord *dbWord, ET9BOOL forceRescore, ALGORITHM_TYPE searchAlgorithm)
{
    /* We only start over if we're not rescoring the suffix, and we only start over with forceRescore, */
    /* so we won't loop indefinitely. */
    SBYTE2  penaltyKeyIndex, fixedLimit2 = 0, slopeCount;
    SBYTE2  checkKeyIndex;
    SBYTE2  transposed = 0, bestMatchType = 0, bestMatchIPIndex = 0, bestMatchPosIndex = 0;
    SBYTE2  bestMatchSkippedIPs = 0, omitted = 0, omitNowPos = 0, omitNowPosActual = 0;
    BYTE2   bestMatchScore = 0, bestMatchDistance = 0;
    ET9BOOL    dualSuffixMatch = _FALSE;
    ET9BOOL    checkSuffixMatches = _FALSE, callCheckKeyMatches = _FALSE, useBestMatch = _FALSE;
    ET9BOOL    swappedNext = _FALSE, swappedPrev = _FALSE, omitKeySwapped = _FALSE;
    float   skipPenaltyKeyOmitTranspose = 0.0, skipPenaltyIPSum = 0.0, IPskipPenalty = 0.0;
#if DEBUG_LOG_MATCH_TRACE
    SBYTE2 lastKeyScored;
#endif
#if DEBUG_LOG_MATCH_TRACE
    if (_SWCSearchDB_IsDebugText(pThis, dbWord) > 0)
    {
        if (pThis->finalScoringPass || forceRescore)
            pThis->bBreakHere = _TRUE;    /* Catch-all breakpoint opportunity */
        else
            pThis->bBreakHere = _FALSE;    /* Catch-all breakpoint opportunity */
    }
#else
    ET9_UNUSED(forceRescore);
#endif
    pThis->swapPos = pThis->omitPos = pThis->lastChangeIndex = 0;
    pThis->thisWord = dbWord;      /* provide access through Search class variables */
    pThis->maxKeyErrorCountCurrent = pThis->maxKeyErrorCount[pThis->m_wSearchLevel];
    if ((dbWord->textLen <= ((5 * pThis->maxKeyErrorCountCurrent) / 2)) && (pThis->maxKeyErrorCountCurrent > 1))
        pThis->maxKeyErrorCountCurrent--;
    pThis->maxKeyErrorCountActual = pThis->maxKeyErrorCountCurrent + 1;

    pThis->reScoreSuffix = _TRUE;

    pThis->keyLimit = (SBYTE2)dbWord->length;           /* Init so compiler is quiet... */
    pThis->keyIndex = pThis->ipIndex = pThis->keyIndexM1 = 0;
    pThis->exitLoop = _FALSE;

    /* Initialize word scores (reset since we may be re-cycling this Word record from a previous call) */
    dbWord->avDistance = 0.0;
    pThis->keySeqLength = (SBYTE2)dbWord->length;
    {
        SBYTE2 i;
        for (i = 0; i < pThis->keySeqLength; i++)
        {
            pThis->keys[i] = dbWord->keys[i];
            pThis->m_keyRepeats[i] = dbWord->keyRepeats[i];
            pThis->keyFlags[i] = NO_CHANGE;
            pThis->skippedIPsCount[i] = 0;
            pThis->hasSkippedIPs[i] = _FALSE;
            pThis->skipPenaltyKey[i] = 0;
            pThis->slopeFactorKey[i] = 0.0;
            pThis->ipIndexKey[i] = -1;         /* Flag as unitialized value */
            dbWord->matchPosIndex[i] = 0;
        }
    }

    pThis->transposeCount = pThis->omitCount = pThis->omissionCount = omitted = pThis->substituteCount = pThis->vowelTransposeCount = 0;
    pThis->skippedIPsWord = 0;
    pThis->skipPenaltyWord = 0.0;
    {
        _SWPoint keyLoc;
        SWDbm_getKeyCenterScaled(pThis->m_backend->m_pDbm, pThis->keys[0], &keyLoc);        /* Get location of key */
        pThis->wordMinX = pThis->wordMaxX = keyLoc.x;
        pThis->wordMinY = pThis->wordMaxY = keyLoc.y;
    }

    {
        SWCIPTableRow *lastIP = pThis->m_aIPTable[pThis->m_wIPTableCount - 1];
        if (lastIP->m_IPType == SoftUp)
        {
            pThis->reScoreSuffix = _TRUE;
            if ((lastIP->m_DoubleIPIndex == 0) && (pThis->m_wIPTableCount > 3))
                lastIP = pThis->m_aIPTable[pThis->m_wIPTableCount - 2];
        }
        pThis->lastKeyMatchesPenUp = (ET9BOOL)(_SWCSearchDB_GetIPWDistance(pThis, lastIP, pThis->keys[pThis->keySeqLength - 1]) != 0);
        pThis->finalKeyScoreAdjusted = _FALSE;
    }

    if (pThis->reScoreSuffix)      /* Score to end of word if suffix scoring failed to account for split DoubleLetter */
    {
        pThis->keyLimit = pThis->keySeqLength;
        pThis->keyLimitSuffix = pThis->keyLimit + 1;
        dualSuffixMatch = checkSuffixMatches = _FALSE;
        pThis->dualMatch = NO_PATTERN_MATCH;
        pThis->ipLimitSuffix = pThis->m_wIPTableCount;
        pThis->fixedLimitSuffix = _SWCSearchDB_GetZ1FixedDataSize(pThis) - 1;
    }
    fixedLimit2 = _SWCSearchDB_GetZ1FixedDataSize(pThis) - 1;


    /* Initialize flags and indices for double IPs and DoubleLetters (up to end of keys to be scored) */
    _SWCSearchDB_SetDoubleIndicesFromKeyRepeats(pThis, pThis->m_keyRepeats, pThis->keySeqLength);
    /* Initialize noDoubleGesture field */
    if (pThis->doubleKeyCount > 0)
        dbWord->noDoubleGesture = _TRUE;     /* Flag this word as entered with no Double Gesture despite presence of double Letter in word */
    else
        dbWord->noDoubleGesture = _FALSE;
    pThis->isCandidate = _TRUE;             /* Assume match until we find otherwise */
    pThis->exitLoop = _FALSE;
    callCheckKeyMatches = _TRUE;
    pThis->nextKeyCheckAlternateMatches = _FALSE;
    useBestMatch = _FALSE;
    bestMatchIPIndex = -1;          /* Init to invalid value */
    pThis->lastKey = SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);       /* Init to invalid (nonexistant) key */
    pThis->lastSkipPosIndex = 0;
    pThis->lastOmittedKey = -1;
    pThis->multipleIPsTotal = 0;
    pThis->rawDist = 0;
    pThis->rawScore = 0;
    pThis->weightSum = 0.0;
    pThis->keyIndex = pThis->keyIndexMax = pThis->ipIndex = pThis->keyIndexM1 = 0;
    pThis->ipData = pThis->m_aIPTable[0];
    pThis->seg1Data = NULL;
    pThis->seg2Data = pThis->m_aIPTable[1];
#if INTERNAL_STATISTICS
    /*if (pThis->finalScoringPass) */
    /*    dbWord->pathSeg1Len8 = pThis->seg2Data->m_SegmentLen8; */
#endif
    if (pThis->m_wIPTableCount >= 3)
        pThis->seg3Data = pThis->m_aIPTable[2];
    else
        pThis->seg3Data = NULL;

    /* End of initForScoring section... */

    /* Main key scoring loop... */
    while ((pThis->keyIndex < pThis->keyLimit) && (pThis->ipIndex < pThis->m_wIPTableCount) && !pThis->exitLoop)
    {
        /* key2 cannot match PenDown unless DoubleKey at start */
        _SWCSearchDB_SetKeyDistancesFromKeyRepeats(pThis, fixedLimit2);
        if (pThis->keyIndex > pThis->keyIndexMax)
            pThis->keyIndexMax = pThis->keyIndex;
        pThis->ipsRemaining = pThis->ipLimitSuffix - pThis->ipIndex;
        pThis->oddPathPenalty = (float)0.0;

        if (callCheckKeyMatches)
            _SWCSearchDB_CheckKeyMatches(pThis, dbWord->matchPosIndex, pThis->fixedLimitSuffix, _TRUE);
        else
        {
            if (pThis->ipIndex == bestMatchIPIndex)
            {
                pThis->matchKey = bestMatchType;
                if (pThis->matchKey != OMIT_CURRENT_KEY_NOW)
                {
                    _SWCSearchDB_CheckKeyMatches(pThis, dbWord->matchPosIndex, pThis->fixedLimitSuffix, _FALSE);
                    if (pThis->matchKey != bestMatchType)  /* If attempted match failed, see if preceding key should actually be deleted */
                    {
                        if (pThis->matchKey == OMIT_TRANSPOSED_KEY)    /* If original pre-suffix key was transposed, then delete transposed key now */
                        {               /*   and back-track with checkSuffixMatches = true to re-process preceding key (original pre-suffix key) */
                            checkSuffixMatches = _TRUE;          /* Perform check only once */
                        }
                        /* If preceding key score or distance was at least double the current key's, and if the */
                        /* best match found is consistent with the key prior to the preceding key, then delete the */
                        /* preceding key instead.  Compare distance as well as score since raw segment scores and raw IP scores */
                        /* are "apples and oranges" */
                        else if ((pThis->keyIndex > 2) &&
                            ((pThis->rawScoreKey[pThis->keyIndex - 2] > (2 * (BYTE4)bestMatchScore)) ||
                            (pThis->rawDistKey[pThis->keyIndex - 2] > (2 * (BYTE4)bestMatchDistance))))
                        {
                            _SWPoint matchKeyPos1, bestMatchKeyPos;
                            SBYTE2 matchKeyPosIndex1;
                            float   bestMatchSlopeDifFactor;
                            ET9BOOL isSegmentMatch = (ET9BOOL)((bestMatchType == THIS_SEGMENT_MATCH) || (bestMatchType == DOUBLE_KEYS_TO_SEGMENT_MATCH));
                            matchKeyPosIndex1 = dbWord->matchPosIndex[pThis->keyIndex - 3];
                            matchKeyPos1 = _SWCSearchDB_GetZ1FixedPoint(pThis, matchKeyPosIndex1);
                            bestMatchKeyPos = _SWCSearchDB_GetZ1FixedPoint(pThis, bestMatchPosIndex);

                            /* If the current key matching is valid when the preceding key is omitted */
                            if (_SWCSearchDB_KeysMatchPoints(pThis, pThis->keys[pThis->keyIndex - 3], pThis->key1, pThis->key2, isSegmentMatch, _FALSE, _FALSE, matchKeyPos1, bestMatchKeyPos, matchKeyPosIndex1, bestMatchPosIndex,
                                                matchKeyPos1, bestMatchKeyPos, matchKeyPosIndex1, bestMatchPosIndex, &bestMatchSlopeDifFactor, 0, 0, 0, 0, _TRUE))
                            {
                                pThis->keyIndex--;         /* Delete the preceding key */
                                pThis->matchKey = OMIT_CURRENT_KEY_NOW;
                                pThis->lastKey = pThis->keys[pThis->keyIndex - 2];           /* Save new values as lastKey */
                                pThis->lastMatchKeyLoc = matchKeyPos1;
                                pThis->lastMatchKeyPos = matchKeyPos1;
                                pThis->lastMatchKeyLocIndex = matchKeyPosIndex1;
                                pThis->lastMatchKeyPosIndex = matchKeyPosIndex1;
                                pThis->altLastMatchKeyLoc = matchKeyPos1;
                                pThis->altLastMatchKeyPos = matchKeyPos1;
                                pThis->altLastMatchKeyLocIndex = 0;
                                pThis->altLastMatchKeyPosIndex = 0;
                                checkSuffixMatches = _TRUE;          /* Perform check again after previous key is omitted */
                                useBestMatch = _TRUE;                /* Use already determined match location */
                            }
                        }
                    }
                    else
                    {
                        if ((pThis->lastSkipPosIndex || bestMatchSkippedIPs) && (pThis->lastOmittedKey > 0) && (pThis->keyIndex == (pThis->lastOmittedKey + 1)) && (pThis->substituteCount < pThis->omissionCount))
                        {
                            pThis->substituteCount++;
                            pThis->lastOmittedKey = -1;        /* Make sure omitted key counted as substitution only once */
                        }
                    }
                }
                callCheckKeyMatches = _TRUE;
            }
            else
            {
                if (!pThis->IP1isArtificial)
                    bestMatchSkippedIPs++;
                pThis->matchKey = NO_PATTERN_MATCH;
            }
        }

/*      pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor; */

#if DEBUG_LOG_MATCH_TRACE
        /* Save matching results for debugging... */
        AlwaysAssert(pThis->ipData != NULL);
        st[pThis->keyIndexM1].p_IPType = pThis->ipData->m_IPType;
        st[pThis->keyIndexM1].matchKey = pThis->matchKey;
        st[pThis->keyIndexM1].ipIndex = pThis->ipIndex;
        st[pThis->keyIndexM1].matchKeyPos = pThis->matchKeyPos;
        st[pThis->keyIndexM1].matchKeyIndex = pThis->matchKeyPosIndex;
        if (debugThis)
            Log(SWLogger_DEBUG, TEXT("st[%d]: %d, %2d, %2d, (%3d, %3d), %2d\n"), pThis->keyIndexM1, pThis->ipData->m_IPType, pThis->matchKey, pThis->ipIndex, pThis->matchKeyPos.x, pThis->matchKeyPos.y, pThis->matchKeyPosIndex);
#endif

        /* Determine how to advance IPs and Keys... */
        penaltyKeyIndex = pThis->keyIndexM1;     /* Record any assessed penalty for proper key. KeyIndex advances below for certain cases. */
        if (pThis->matchKey == DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH)
            pThis->finalMatchPosIndex = pThis->matchLocExitIndex[pThis->keyIndexM1];
        else if ((pThis->matchKey >= IP_MATCH) && (pThis->matchKey <= SEGMENT_MATCH_ONLY))
            pThis->finalMatchPosIndex = pThis->matchKeyPosIndex;

        /* CK Note: finalMatchPosIndex may not be initialized - also check use of matchPosIndex[] in suffixes - probably can be replaced with one or two values that need to be preserved... */

        pThis->matchKeyType[pThis->keyIndexM1] = pThis->matchKey;
        pThis->hasSegmentMatch[pThis->keyIndexM1] = _FALSE;
        switch (pThis->matchKey)
        {
        case NO_PATTERN_MATCH:
            pThis->advanceIP = _TRUE;
            if (pThis->requiredIP)
                pThis->skippedIPsCount[pThis->keyIndexM1] += 1;     /* Record that this IP was skipped in current matching */
            if (!pThis->IP1isArtificial)
                pThis->hasSkippedIPs[pThis->keyIndexM1] = _TRUE;
            pThis->advanceKey = _FALSE;     /* Remain on same key */
            pThis->finalKey = _FALSE;       /* Even if we were on final key, we still haven't matched it */
            break;

        case OMIT_CURRENT_KEY_NOW:
            /* Record position of omission, adjusting for previous omission (if any) so position */
            /*   in original word is recorded */
            omitNowPos = omitNowPosActual = pThis->keyIndexM1;
            omitKeySwapped = _FALSE;             /* Assume no transposition found */
            /* Check for previous transposition that may be invalidated by omission */
            if (_SWCSearchDB_checkTranspositions(pThis, &swappedNext, &swappedPrev, pThis->keyLimit))
            {
                /* Determine if key to be omitted is a transposed key */
                if ((omitNowPos == pThis->swapPos) || (swappedNext && (omitNowPos == (pThis->swapPos + 1))) || (swappedPrev && (omitNowPos == (pThis->swapPos - 1))))
                {
                    if ((pThis->transposeCount <= 0) || (pThis->keyFlags[pThis->swapPos] == NO_CHANGE))
                    {
                        _SWCSearchDB_FailCandidate(pThis);
                        return(-1);
                    }
                    pThis->transposeCount--;
                    pThis->keyFlags[pThis->swapPos] = NO_CHANGE;
                    if ((pThis->vowelTransposeCount > 0) && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos], _TRUE) &&
                        ((swappedNext && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos + 1], _TRUE)) ||
                         (swappedPrev && _SWCSearchDB_isVowelKey(pThis, pThis->keys[pThis->swapPos - 1], _TRUE))))
                        pThis->vowelTransposeCount--;
                    omitNowPosActual = pThis->swapPos;
                    omitKeySwapped = _TRUE;          /* Flag that omitted key was transposed */
                }
            }
            omitted = _SWCSearchDB_RecordKeyOmissionFromKeyRepeats(pThis, omitNowPos, omitNowPosActual);
            if (omitted > 0)
            {
                if (omitKeySwapped)
                {
                    checkSuffixMatches = _TRUE;
                    pThis->keyIndex = pThis->keyLimitSuffix - 1;      /* Re-process key preceding suffix */
                }
                checkKeyIndex = pThis->keyIndex;       /* RestoreEnvironment may decrement keyIndex if we land on a double key */
                pThis->omitPos = omitNowPos;
                _SWCSearchDB_RestoreEnvironmentFromKeyRepeats(pThis, omitted, dbWord->matchPosIndex, &pThis->skipPenaltyWord, &pThis->skippedIPsWord);
                /* If RestoreEnvironmentFromKeyRepeats() changed keyIndex, it has been reset assuming advanceKey == _TRUE */
                if (!pThis->advanceKey && (pThis->keyIndex != checkKeyIndex))
                    pThis->advanceKey = _TRUE;
                pThis->finalKey = _FALSE;       /* Even if we were on final key, we still haven't matched it */
            }
            break;

        case OMIT_CURRENT_KEY:
        case OMIT_TRANSPOSED_KEY:
        case NEXT_KEY_IP_MATCH:
        case NEXT_KEY_SEGMENT_MATCH:
            /* SavedCodeSegments/273 - PERFORM_FUTURE_MATCH_CHECK code */
            DebugAssert(!pThis->IP1isArtificial || !pThis->advanceIP);
            transposed = _SWCSearchDB_CheckTransposeOmitKey(pThis, dbWord->matchPosIndex, fixedLimit2, &pThis->skipPenaltyWord, &pThis->skippedIPsWord);
            /* SavedCodeSegments/274 - PERFORM_FUTURE_MATCH_CHECK code */
            if (transposed)
            {
            }
            else
            {
                pThis->advanceIP = _TRUE;
                pThis->matchKey = NO_PATTERN_MATCH;  /* Current IP is being skipped */
                if (pThis->requiredIP)
                    pThis->skippedIPsCount[pThis->keyIndexM1] += 1;     /* Record that this IP was skipped in current matching */
                if (!pThis->IP1isArtificial)
                    pThis->hasSkippedIPs[pThis->keyIndexM1] = _TRUE;
                pThis->advanceKey = _FALSE;     /* Remain on same key */
                pThis->finalKey = _FALSE;       /* Even if we were on final key, we still haven't matched it */
            }
            break;

        case IP_MATCH:
            /* If Final suffix key has dual match, check if root also requires dual-matching IP */
            if (dualSuffixMatch && (pThis->ipIndex == (pThis->m_wIPTableCount - 1)))
            {
                pThis->dualMatch = SEGMENT_MATCH_ONLY;     /* Force suffix dual match to segment */
            }
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->key1IP1;
            pThis->rawDistKey[pThis->keyIndexM1] = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);
            if (pThis->finalKeyScoreAdjusted)
            {
                BYTE2 segDistance = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg1Data, pThis->key1);
                if (segDistance && (segDistance < DISTANCE8_MAX))
                    pThis->rawDistKey[pThis->keyIndexM1] = ((2 * segDistance) + pThis->rawDistKey[pThis->keyIndexM1]) / 3;
            }
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = pThis->ipData->m_fIPWeight;
            pThis->matchKeyLocs[pThis->keyIndexM1] = pThis->ipData->m_IPLocation;
            pThis->advanceIP = _TRUE;
            break;

        case THIS_SEGMENT_MATCH:
            pThis->rawDistKey[pThis->keyIndexM1] = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg1Data, pThis->key1);
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->key1Seg1;
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = _SWCSearchDB_GetSegmentMatchWeight(pThis, pThis->seg1Data, pThis->key1);
            pThis->matchKeyLocs[pThis->keyIndexM1] = _SWCSearchDB_GetZ1FixedPoint(pThis, dbWord->matchPosIndex[pThis->keyIndexM1]);
            pThis->hasSegmentMatch[pThis->keyIndexM1] = _TRUE;
            if (pThis->ipIndex > 0)
                pThis->ipIndexKey[pThis->keyIndexM1] = pThis->ipIndex - 1;     /* Current IP (at ipIndex) not actually matched yet */
            pThis->advanceIP = _FALSE;
            break;

        case NEXT_SEGMENT_MATCH:
            pThis->rawDistKey[pThis->keyIndexM1] = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg2Data, pThis->key1);
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->key1Seg2;
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = _SWCSearchDB_GetSegmentMatchWeight(pThis, pThis->seg2Data, pThis->key1);
            pThis->matchKeyLocs[pThis->keyIndexM1] = _SWCSearchDB_GetZ1FixedPoint(pThis, dbWord->matchPosIndex[pThis->keyIndexM1]);
            pThis->hasSegmentMatch[pThis->keyIndexM1] = _TRUE;
            pThis->advanceIP = _TRUE;
            if (pThis->requiredIP)
                pThis->skippedIPsCount[pThis->keyIndexM1] += 1;     /* Record that this IP was skipped in current matching */
            if (!pThis->IP1isArtificial)
                pThis->hasSkippedIPs[pThis->keyIndexM1] = _TRUE;
            break;

        case DOUBLE_KEYS_TO_SINGLE_IP_MATCH:
#if DEBUG_LOG_MATCH_TRACE
            st[pThis->keyIndexM1].p_IPType = pThis->ipData->m_IPType;
            st[pThis->keyIndexM1].matchKey = pThis->matchKey;
            st[pThis->keyIndexM1].ipIndex =  pThis->ipIndex;
            st[pThis->keyIndexM1].matchKeyPos = pThis->matchKeyPos;
            st[pThis->keyIndexM1].matchKeyIndex = pThis->matchKeyPosIndex;
            if (debugThis)
                Log(SWLogger_DEBUG, TEXT("st[%d]: %d, %2d, %2d, (%3d, %3d), %2d - double keys to single ip\n"), pThis->keyIndexM1, pThis->ipData->m_IPType, pThis->matchKey, pThis->ipIndex, pThis->matchKeyPos.x, pThis->matchKeyPos.y, pThis->matchKeyPosIndex);
#endif
            /* If Final suffix key has dual match, check if root also requires dual-matching IP */
            if (dualSuffixMatch && (pThis->ipIndex == (pThis->m_wIPTableCount - 1)))
                pThis->dualMatch = SEGMENT_MATCH_ONLY;     /* Force suffix dual match to segment */
            pThis->rawDistKey[pThis->keyIndexM1] = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);

            /* Add both score and weight for Double IP twice (associated with SlopeFactor) */
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->key1IP1;
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = pThis->ipData->m_fIPWeight;
            pThis->matchKeyLocs[pThis->keyIndexM1] = pThis->ipData->m_IPLocation;
            if (pThis->nextDoubleKeyIndex < 1)
            {
                _SWCSearchDB_FailCandidate(pThis);
                return(-1);
            }
            pThis->advanceIP = _TRUE;
            pThis->finalKey = (ET9BOOL)(pThis->keyIndex == pThis->keyLimit);
            break;

        case DOUBLE_KEYS_TO_SEGMENT_MATCH:          /* !!! Don't set advanceIP = _TRUE! */
#if DEBUG_LOG_MATCH_TRACE
            st[pThis->keyIndexM1].p_IPType = pThis->ipData->m_IPType;
            st[pThis->keyIndexM1].matchKey = pThis->matchKey;
            st[pThis->keyIndexM1].ipIndex =  pThis->ipIndex;
            st[pThis->keyIndexM1].matchKeyPos = pThis->matchKeyPos;
            st[pThis->keyIndexM1].matchKeyIndex = pThis->matchKeyPosIndex;
            if (debugThis)
                Log(SWLogger_DEBUG, TEXT("st[%d]: %d, %2d, %2d, (%3d, %3d), %2d - double keys to segment\n"), pThis->keyIndexM1, pThis->ipData->m_IPType, pThis->matchKey, pThis->ipIndex, pThis->matchKeyPos.x, pThis->matchKeyPos.y, pThis->matchKeyPosIndex);
#endif
            pThis->rawDistKey[pThis->keyIndexM1] = _SWCSearchDB_GetSegmentDistance8(pThis, pThis->seg1Data, pThis->key1);
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->key1Seg1;
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = _SWCSearchDB_GetSegmentMatchWeight(pThis, pThis->seg1Data, pThis->key1);
            pThis->matchKeyLocs[pThis->keyIndexM1] = _SWCSearchDB_GetZ1FixedPoint(pThis, dbWord->matchPosIndex[pThis->keyIndexM1]);
            pThis->hasSegmentMatch[pThis->keyIndexM1] = _TRUE;
            if (pThis->ipIndex > 0)
                pThis->ipIndexKey[pThis->keyIndexM1] = pThis->ipIndex - 1;     /* Current IP (at ipIndex) not actually matched yet */
            else
                pThis->ipIndexKey[pThis->keyIndexM1] = 0;               /* Current IP (at ipIndex) not actually matched yet */
            if (pThis->nextDoubleKeyIndex < 1)
            {
                _SWCSearchDB_FailCandidate(pThis);
                return(-1);
            }
            pThis->advanceIP = _FALSE;
            pThis->finalKey = (ET9BOOL)(pThis->keyIndex == pThis->keyLimit);
            break;

        case MULTIPLE_KEYS_TO_MERGED_IP_MATCH:
#if DEBUG_LOG_MATCH_TRACE
            st[pThis->keyIndexM1].p_IPType = pThis->ipData->m_IPType;
            st[pThis->keyIndexM1].matchKey = pThis->matchKey;
            st[pThis->keyIndexM1].ipIndex = pThis->ipIndex;
            st[pThis->keyIndexM1].matchKeyPos = pThis->matchKeyPos;
            st[pThis->keyIndexM1].matchKeyIndex = pThis->matchKeyPosIndex;
            if (debugThis)
                Log(SWLogger_DEBUG, TEXT("st[%d]: %d, %2d, %2d, (%3d, %3d), %2d - double keys to merged ip\n"), pThis->keyIndexM1, pThis->ipData->m_IPType, pThis->matchKey, pThis->ipIndex, pThis->matchKeyPos.x, pThis->matchKeyPos.y, pThis->matchKeyPosIndex);
#endif
            /* If Final suffix key has dual match, check if root also requires dual-matching IP */
            if (dualSuffixMatch && (pThis->ipIndex == (pThis->m_wIPTableCount - 1)))
                pThis->dualMatch = SEGMENT_MATCH_ONLY;     /* Force suffix dual match to segment */

            pThis->rawDistKey[pThis->keyIndexM1] = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key1);
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->key1IP1;
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = pThis->weightSumKey[pThis->keyIndex] = pThis->ipData->m_fIPWeight;
            pThis->matchKeyLocs[pThis->keyIndexM1] = pThis->matchKeyLocs[pThis->keyIndex] = pThis->ipData->m_IPLocation;
            pThis->ipIndexKey[pThis->keyIndexM1] = pThis->ipIndexKey[pThis->keyIndex] = pThis->ipIndex;      /* Record current matched IP for both matched keys */
            /* Scoring for second key */
            pThis->rawDistKey[pThis->keyIndex] = _SWCSearchDB_GetIPDistance8(pThis, pThis->ipData, pThis->key2);
            pThis->rawScoreKey[pThis->keyIndex] = pThis->key2IP1;
            pThis->slopeFactorKey[pThis->keyIndex] = DEFAULT_UNKNOWN_SLOPE_FACTOR;
            pThis->advanceIP = _TRUE;
            pThis->keyIndex++;     /* Skip over both matched keys */
            pThis->keyIndexM1 = pThis->keyIndex - 1;
            pThis->finalKey = (ET9BOOL)(pThis->keyIndex == pThis->keyLimit);
            break;

        /* SavedCodeSegments/SearchDB.cpp/95 */

        case DOUBLE_KEYS_TO_MULTIPLE_IPS_MATCH:
            dbWord->noDoubleGesture = _FALSE;        /* If any doubleLetter gesture is detected, clear noDoubleGesture flag */
            /* Skip over both keys and all matched IPs */
            pThis->ipIndex = (SBYTE2)(pThis->ipIndex + pThis->multipleIPCount);
            pThis->ipIndexKey[pThis->keyIndex] = pThis->ipIndex;
            /* If Final suffix key has dual match, check if root also requires dual-matching IP */
            if (dualSuffixMatch && (pThis->ipIndex == (pThis->m_wIPTableCount - 1)))
                pThis->dualMatch = SEGMENT_MATCH_ONLY;     /* Force suffix dual match to segment */
#if DEBUG_LOG_MATCH_TRACE
            {
                SWCIPTableRow *ipNext = NULL;
                if (pThis->ipIndex < pThis->m_wIPTableCount)
                    ipNext = pThis->m_aIPTable[pThis->ipIndex];
                if (ipNext != NULL)
                    st[pThis->keyIndex].p_IPType = ipNext->m_IPType;
                st[pThis->keyIndex].matchKey = pThis->matchKey;
                st[pThis->keyIndex].ipIndex = pThis->ipIndex;
                st[pThis->keyIndexM1].matchKeyPos = st[pThis->keyIndex].matchKeyPos = pThis->matchKeyPos;
                st[pThis->keyIndexM1].matchKeyIndex = st[pThis->keyIndex].matchKeyIndex = pThis->matchKeyPosIndex;
                if (debugThis)
                    Log(SWLogger_DEBUG, TEXT("st[%d,%d]: %d, %2d, %2d, (%3d, %3d), %2d\n"), pThis->keyIndex, pThis->keyIndexM1, pThis->ipData->m_IPType, pThis->matchKey, pThis->ipIndex, pThis->matchKeyPos.x, pThis->matchKeyPos.y, pThis->matchKeyPosIndex);
            }
#endif
            pThis->rawDistKey[pThis->keyIndexM1] = pThis->keyMultipleIPsDistance;
            /* Add both score and weight for Double Key twice (associated with SlopeFactor) */
            pThis->rawScoreKey[pThis->keyIndexM1] = pThis->keyMultipleIPs;
            pThis->slopeFactorKey[pThis->keyIndexM1] = pThis->matchSlopeDifFactor;
            pThis->weightSumKey[pThis->keyIndexM1] = MultipleIPsWeight;
            pThis->matchKeyLocs[pThis->keyIndexM1] = pThis->matchKeyPos;      /* Save calculated match location for calculating final slopeFactor ("shopping" case) */
            if (pThis->nextDoubleKeyIndex < 1)
            {
                _SWCSearchDB_FailCandidate(pThis);
                return(-1);
            }
            pThis->advanceIP = _TRUE;   /* Skip over all matched IPs */
            pThis->finalKey = (ET9BOOL)(pThis->keyIndex == pThis->keyLimit);
            break;
        }

        if (pThis->isCandidate)
        {
            /* Add any penalty points incurred for current matching */
            float thisPenalty = _SWCSearchDB_GetSkippingPenalty(pThis, pThis->ipData, pThis->matchKey, pThis->advanceIP, &pThis->skippedIPsWord, &IPskipPenalty, _FALSE, pThis->oddPathPenalty);
            pThis->skipPenaltyKey[penaltyKeyIndex] += thisPenalty;
            pThis->skipPenaltyWord += thisPenalty;
#if DEBUG_SHOW_MATCH_TRACE
            if (debugThis)
            {
                /*Log(SWLogger_DEBUG, TEXT(" Current penalty: %f, delta: %f \n"), pThis->skipPenaltyWord, thisPenalty); */
            }
#endif
            if (pThis->skipPenaltyWord >= pThis->maxCandidateIPPenalty)
            {
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    Log(SWLogger_DEBUG, TEXT(" Word %s FAILED due exceeding maxCandidateIPPenalty (%.2f)!\r\n"), pThis->thisWord->externalText, pThis->maxCandidateIPPenalty);
                    Log(SWLogger_DEBUG, TEXT(" Current penalty: %f \n"), pThis->skipPenaltyWord);
                }
#endif
                _SWCSearchDB_FailCandidate(pThis);
#if !DEBUG_SHOW_MATCH_TRACE_CONTINUE_AFTER_FAIL
                return(-1);
#endif
            }
            if (!pThis->advanceKey)
            {
                pThis->keyIndex--;             /* Remain on same key */
                if (pThis->key1IsDoubleKey && (pThis->nextDoubleKeyIndex > 0))        /* Still on same doubleKey */
                    pThis->nextDoubleKeyIndex--;
            }

            /* Advance to next IP if current word is still a candidate */
            if (pThis->isCandidate)
            {
                if (pThis->advanceIP)      /* Even if we are exiting the loop, we need to advance past the last matched IP so no penalty is assessed below */
                {
                    pThis->seg1Data = pThis->seg2Data;
                    pThis->seg2Data = pThis->seg3Data;
                    pThis->ipIndex++;
                    if (pThis->ipIndex < pThis->m_wIPTableCount)      /* Main loop will exit when ipIndex is >= m_wIPTableCount */
                    {
                        pThis->ipData = pThis->seg1Data = pThis->m_aIPTable[pThis->ipIndex];
                        pThis->seg2Data = ((pThis->ipIndex + 1) < pThis->m_wIPTableCount) ? pThis->m_aIPTable[pThis->ipIndex + 1] : NULL;
                        pThis->seg3Data = ((pThis->ipIndex + 2) < pThis->m_wIPTableCount) ? pThis->m_aIPTable[pThis->ipIndex + 2] : NULL;
                    }
                    /* SavedCodeSegments/SearchDB.cpp/90 */
                }
            }
        }
    }  /* END while ((keyIndex < keyLimit) && (ipIndex < pThis->m_wIPTableCount) && !pThis->exitLoop) */
#if DEBUG_LOG_MATCH_TRACE
    lastKeyScored = pThis->keyIndex;
#endif

    /* Failure if we did not match all keys of word before running out of IPs */
    if (!pThis->finalKey || !pThis->isCandidate)
    {
        _SWCSearchDB_FailCandidate(pThis);
#if !DEBUG_SHOW_MATCH_TRACE_CONTINUE_AFTER_FAIL
        return(-1);
#endif
    }
    else
    {
        /* If reScoreSuffix is _FALSE, all the quantities in addSuffixScores() have already been integrated into the current scoring results: */
        /*      omitCount, substituteCount, vowelTransposeCount, skippedIPsWord, and skipPenaltyWord all include the corresponding results */
        /*      for the final (N - 1) keys for a suffix of length N. */
        /* What remains to be integrated in the scoring results are: */
        /*      rawDistNm1+, rawScoreNm1+, penaltyRawScoreNm1+, weightSumNm1+, */
        /*      slopeScoreNm1[suffixMatch]+, slopeFactorTotalNm1[suffixMatch]+/slopeCount+, lastKeyPenalty[suffixMatch]+, lastKeySkippedIPs[suffixMatch]+, */
        SBYTE2 index = pThis->ipIndex;
        SBYTE2 checkLimit = pThis->m_wIPTableCount - 1;
        SBYTE2 skippedIPsAtEnd = 0;
        float skipPenaltyAtEnd = 0.0;

        if (!pThis->reScoreSuffix)
        {
        }
        else /* if (pThis->reScoreSuffix) */
            checkLimit = pThis->m_wIPTableCount;

        if (pThis->ipIndex < checkLimit)
        {
            index = pThis->ipIndex;
            while (pThis->isCandidate && (index < checkLimit))
            {
                skipPenaltyAtEnd += _SWCSearchDB_GetSkippingPenalty(pThis, pThis->ipData, NO_PATTERN_MATCH, _TRUE, &skippedIPsAtEnd, &IPskipPenalty, _FALSE, (float)0.0);
                if ((pThis->skipPenaltyWord + skipPenaltyAtEnd) >= pThis->maxCandidateIPPenalty)
                {
                    _SWCSearchDB_FailCandidate(pThis);
#if !DEBUG_SHOW_MATCH_TRACE_CONTINUE_AFTER_FAIL
                    return(-1);
#endif
                }
                index++;
                if (index < checkLimit)
                    pThis->ipData = pThis->m_aIPTable[index];
            }
        }

        if (pThis->isCandidate)
        {
            /* Calculate final scoring for word */
            /* If rescoreSuffix is still _FALSE, then the following already include the totals for the suffix: */
            /*    omitCount, etc.; skippedIPs */
            /* */
            pThis->rawDist = 0;
            pThis->rawScore = 0;
            pThis->rawSlopeScore = 0.0;
            pThis->weightSum = 0.0;
            pThis->slopeFactorTotal = 0.0;
            pThis->penaltyRawScore = 0.0;
            slopeCount = 0;
            pThis->skippedIPsWord = (SBYTE2)(pThis->skippedIPsWord + skippedIPsAtEnd);
            pThis->skipPenaltyWord = (SBYTE2)(pThis->skipPenaltyWord + skipPenaltyAtEnd);
            /* Calculate totals accumulated for keys scored above */
            if (pThis->substituteCount > pThis->omitCount)
                pThis->substituteCount = pThis->omitCount;
            if (pThis->vowelTransposeCount > pThis->transposeCount)
                pThis->vowelTransposeCount = pThis->transposeCount;
            skipPenaltyKeyOmitTranspose = ((pThis->transposeCount - pThis->vowelTransposeCount) * KEY_TRANSPOSED_PENALTY) + (pThis->vowelTransposeCount * VOWEL_TRANSPOSED_PENALTY) +
                                          ((pThis->omitCount - pThis->substituteCount) * KEY_OMITTED_PENALTY) + (pThis->substituteCount * KEY_SUBSTITUTED_PENALTY);
            if (skipPenaltyKeyOmitTranspose > pThis->maxCandidateSpellPenalty)
            {
#if DEBUG_LOG_MATCH_TRACE
                if (debugThis)
                {
                    Log(SWLogger_DEBUG, TEXT(" Word %s FAILED due exceeding maxCandidateSpellPenalty (%.2f)!\r\n"), pThis->thisWord->externalText, pThis->maxCandidateSpellPenalty);
                    Log(SWLogger_DEBUG, TEXT(" Spelling penalty: %f \n"), skipPenaltyKeyOmitTranspose);
                }
#endif
                _SWCSearchDB_FailCandidate(pThis);
#if !DEBUG_SHOW_MATCH_TRACE_CONTINUE_AFTER_FAIL
                return(-1);
#endif
            }
            /* Calculate average slope factor for use where no slope factor could be calculated */
            if (pThis->finalScoringPass)
            {
                /* Re-calculate slope factors based on actual (not projected) matching location of each following key */
                SBYTE2 prevKeyIndex, nextKeyIndex;
                SBYTE2 lastKeyIndex = -1;
                SBYTE2 thisKeyIndex = 0;        /* This will always be the preceding key for the first non-repeated key */
                ET9BOOL thisKeyDoubleMatch = _SWCSearchDB_isDoubleGestureMatch(pThis->matchKeyType[0]);
                ET9BOOL lastKeyDoubleMatch = _FALSE;
                float  slopeDifFactor;
                pThis->thisKeyCheckAlternateMatches = pThis->nextKeyCheckAlternateMatches = _FALSE;        /* Match locations have been deternmined - don't check alternates */
                for (pThis->keyIndex = 1; (pThis->keyIndex < pThis->keyLimit) && pThis->isCandidate; pThis->keyIndex++)     /* Don't re-calculate default value of 1.0 at PenDown location in average */
                {
                    ET9BOOL isLastKey;
                    BYTE1 key_1, key_2, key_3;
                    ET9BOOL swappedKey;
                    SBYTE2 matchKeyPoint_Index1;
                    SBYTE2 matchKeyPoint_Index2;
                    SBYTE2 matchKeyPoint_Index3;
                    _SWPoint matchKeyPoint1;
                    _SWPoint matchKeyPoint2;
                    _SWPoint matchKeyPoint3;
                    lastKeyDoubleMatch = thisKeyDoubleMatch;
                    thisKeyDoubleMatch = _SWCSearchDB_isDoubleGestureMatch(pThis->matchKeyType[pThis->keyIndex]);   /* Check for match with Double gesture (don't use lengthEffect on double gesture match) */
                    prevKeyIndex = lastKeyIndex;
                    lastKeyIndex = thisKeyIndex;
                    thisKeyIndex = pThis->keyIndex;
                    nextKeyIndex = pThis->keyIndex + 1;   /* K3 is following key */
                    isLastKey = (ET9BOOL)(nextKeyIndex >= pThis->keyLimit);
                    key_1 = pThis->keys[lastKeyIndex];
                    key_2 = pThis->keys[thisKeyIndex];
                    key_3 = (!isLastKey) ? pThis->keys[nextKeyIndex] : SWDbm_letterKeyCnt(pThis->m_backend->m_pDbm);
                    pThis->isSwappedKey = (!isLastKey && ((pThis->keyFlags[nextKeyIndex] == TRANSPOSED_PREV) || (pThis->keyFlags[nextKeyIndex] == TRANSPOSED_PREV_ONLY)));
                    if (!pThis->isSwappedKey)
                        pThis->isSwappedKey = ((pThis->keyFlags[lastKeyIndex] == TRANSPOSED_NEXT) || ((pThis->keyFlags[pThis->keyIndex] != NO_CHANGE) && (pThis->keyFlags[pThis->keyIndex] != OMIT_KEY_LATER)));
                    pThis->wasSwappedKey = (ET9BOOL)((pThis->keyIndex < pThis->keyLimit) && ((pThis->keyFlags[pThis->keyIndex] == TRANSPOSED_PREV) || (pThis->keyFlags[pThis->keyIndex] == TRANSPOSED_PREV_ONLY)));
                    if (!pThis->wasSwappedKey)
                        pThis->wasSwappedKey = ((pThis->keyFlags[lastKeyIndex] != NO_CHANGE) && (pThis->keyFlags[lastKeyIndex] != OMIT_KEY_LATER));
                    if (!pThis->wasSwappedKey && (prevKeyIndex >= 0))
                        pThis->wasSwappedKey = (pThis->keyFlags[prevKeyIndex] == TRANSPOSED_NEXT);
                    swappedKey = pThis->isSwappedKey || pThis->wasSwappedKey;
                    /* SET UP FOR  KeysMatchPoints() CALL... */
                    pThis->seg1Data = pThis->m_aIPTable[pThis->ipIndexKey[pThis->keyIndex]];
                    matchKeyPoint_Index1 = dbWord->matchPosIndex[lastKeyIndex];
                    matchKeyPoint1 = pThis->matchKeyLocs[lastKeyIndex];
                    matchKeyPoint_Index2 = dbWord->matchPosIndex[thisKeyIndex];
                    matchKeyPoint2 = pThis->matchKeyLocs[thisKeyIndex];
                    matchKeyPoint_Index3 = 0;
                    matchKeyPoint3;
                    _SWPoint_Construct_SB2SB2(&matchKeyPoint3, 0, 0);
                    if (!isLastKey)
                    {
                        if ((nextKeyIndex < pThis->keyLimitSuffix) || pThis->reScoreSuffix)
                        {
                            matchKeyPoint_Index3 = dbWord->matchPosIndex[nextKeyIndex];
                            matchKeyPoint3 = pThis->matchKeyLocs[nextKeyIndex];
                        }
                        else if (nextKeyIndex >= pThis->keyLimitSuffix)
                        {
                        }
                    }
                    pThis->isCandidate = _SWCSearchDB_KeysMatchPoints(pThis, key_1, key_2, key_3, pThis->hasSegmentMatch[pThis->keyIndex], swappedKey, _FALSE,
                                matchKeyPoint1, matchKeyPoint2, matchKeyPoint_Index1, matchKeyPoint_Index2,
                                matchKeyPoint1, matchKeyPoint2, matchKeyPoint_Index1, matchKeyPoint_Index2,
                                &slopeDifFactor, matchKeyPoint_Index3, 0, 0, 0, (ET9BOOL)!(lastKeyDoubleMatch || thisKeyDoubleMatch));
#if DEBUG_SHOW_MATCH_TRACE
                    if (debugThis)
                    {
                        if (!pThis->isCandidate)
                            pThis->bBreakHere = _TRUE;
                        if (pThis->slopeFactorKey[pThis->keyIndex] != slopeDifFactor)
                            pThis->bBreakHere = _TRUE;
                    }
#endif
                    pThis->slopeFactorKey[pThis->keyIndex] = slopeDifFactor;
                }
                /* SavedCodeSegments/SearchDB.cpp/126 */
                {
                    SBYTE2 i;
                    for (i = 1; (i < pThis->keyLimit) && pThis->isCandidate; i++)     /* Don't include default value of 1.0 at PenDown location in average */
                    {
                        if (pThis->rawScoreKey[i] && (pThis->slopeFactorKey[i] > 0.0))
                        {
                            /* SavedCodeSegments/SearchDB.cpp/127 */
                            if (pThis->hasSegmentMatch[i] && (i < (pThis->keyLimit - 1)) )
                            {
                                /* Look at preceding key K1 and following key K3 with respect to segment match key K2 (at */
                                /* match locations M1, M2 and M3 respectively.  Compare ratio of (K1->K2)+(K2->K3)/(K1->K3) */
                                /* to (M1->M3)(path)/(M1->M3)(straight line), and increase the slope factor when */
                                /* this ratio is greater than 1.0.  Use slopeKeyIndex to reference next key in case current key */
                                /* is a double key. */
                                SBYTE2 nextKeyIndex = -1;
                                if (pThis->rawScoreKey[i + 1])     /* If key[i] is NOT the first key of a double key */
                                    nextKeyIndex = i + 1;   /* K3 is following key */
                                else if (i < (pThis->keyLimit - 2))    /* Else if this double key is not the final key */
                                    nextKeyIndex = i + 2;   /* K3 is key that follows the double key */
                                if (nextKeyIndex > 0)
                                {
                                    pThis->slopeFactorKey[i] = _SWCSearchDB_AdjustSegmentSlopeFactor(pThis, dbWord->matchPosIndex, i, nextKeyIndex, pThis->slopeFactorKey[i]);
                                }
                                /* SavedCodeSegments/SearchDB.cpp/128 */
                            }
                            /* SavedCodeSegments/SearchDB.cpp/129 */
                            if (pThis->slopeFactorKey[i] > MAX_SLOPE_FACTOR)
                                pThis->slopeFactorKey[i] = MAX_SLOPE_FACTOR;
                            pThis->slopeFactorTotal += pThis->slopeFactorKey[i];
                            slopeCount++;
                        }
                    }
                }

                if (!slopeCount || (pThis->slopeFactorTotal < 1.0))
                {
                    if (pThis->m_wRequiredIPTableCount > 1)    /* No penalty if only one required IP (e.g. single double-letter IP) */
                    {
                        pThis->avSlopeFactor = DEFAULT_AVERAGE_SLOPE_FACTOR;
                        pThis->penaltySlopeFactor = DEFAULT_PENALTY_SLOPE_FACTOR;
                    }
                    else
                    {
                        pThis->avSlopeFactor = DEFAULT_SLOPE_FACTOR;
                        pThis->penaltySlopeFactor = DEFAULT_SLOPE_FACTOR;
                    }
                }
                else
                {
                    pThis->avSlopeFactor = pThis->slopeFactorTotal / (float)slopeCount;
                    if (slopeCount < (pThis->keySeqLength - 1))
                    {
                        pThis->penaltySlopeFactor = (pThis->slopeFactorTotal + ((float)(pThis->keySeqLength - 1 - slopeCount) * DEFAULT_UNKNOWN_SLOPE_FACTOR)) / (float)(pThis->keySeqLength - 1);
                    }
                    else
                        pThis->penaltySlopeFactor = pThis->avSlopeFactor;
                }
            }
            else
            {
                pThis->avSlopeFactor = pThis->penaltySlopeFactor = DEFAULT_SLOPE_FACTOR;
            }
            skipPenaltyIPSum = skipPenaltyAtEnd;        /* HERE! - This is also an approximation - other IP-skipping penalties added while scoring word */
            {
                SBYTE2 i;
                for (i = 0; (i < pThis->keyLimit) && pThis->isCandidate; i++)
                {
                    if (pThis->hasSkippedIPs[i])
                        skipPenaltyIPSum += pThis->skipPenaltyKey[i];
                    pThis->rawDist += pThis->rawDistKey[i];
                    pThis->weightSum += pThis->weightSumKey[i];
                    if (pThis->rawScoreKey[i])
                    {
                        float key_Score = (float)pThis->rawScoreKey[i];
                        if (pThis->finalScoringPass)
                        {
                            if (pThis->slopeFactorKey[i] > 0.0)
                                key_Score = key_Score * pThis->slopeFactorKey[i];
                            else
                                key_Score = key_Score * pThis->avSlopeFactor;
                            pThis->rawSlopeScore += key_Score;
                        }
                        pThis->rawScore += pThis->rawScoreKey[i];
                        if (pThis->skipPenaltyKey[i] > 0.0)
                        {
                            float localPenalty = sw_min(pThis->skipPenaltyKey[i], MAX_SINGLE_KEY_SCORING_PENALTY);
                            pThis->penaltyRawScore += localPenalty * key_Score;
                        }
                    }
                }
            }
            if (!pThis->reScoreSuffix)
            {
            }
            else
            {
                if (pThis->isCandidate)
                {
                    pThis->skipPenaltyWord += skipPenaltyKeyOmitTranspose;
                }
            }
        }
    }

#if DEBUG_SHOW_MATCH_TRACE_CONTINUE_AFTER_FAIL
    if (pThis->isCandidate || debugThis)   /* Set return values for scoring */
#else
    if (pThis->isCandidate)    /* Set return values for scoring */
#endif
    {
        /* Assess additive score penalties based on maximum of skipped IPs or omitted letters.  This corresponds to */
        /* an assumption that one skipped IP and one omitted letter correspond to one letter substitution in the word. */
        /* NOTE: Consider verifying that the skipped IP and omitted letter occur at the same point in the sequence... */
        SBYTE2 extraSkippedIPs = 0;
        SBYTE2 extraOmittedKeys = 0;
        float shiftPenalty = 0.0;
        float slopeScore;
        float penaltySlopeScore;
        float penaltyFreqScore;
        float penaltyFreqScore_PathOnly;
        if (pThis->skippedIPsWord > pThis->substituteCount)
            extraSkippedIPs = pThis->skippedIPsWord - pThis->substituteCount;
        if (pThis->omitCount > pThis->substituteCount)
            extraOmittedKeys = pThis->omitCount - pThis->substituteCount;

        pThis->penaltyRawDist = (BYTE4)((extraSkippedIPs * SKIPPED_IP_DISTANCE_PENALTY) + (extraOmittedKeys * OMITTED_KEY_DISTANCE_PENALTY) +
                         (pThis->substituteCount * SUBSTITUTED_KEY_DISTANCE_PENALTY) + ((pThis->transposeCount - pThis->vowelTransposeCount) * TRANSPOSED_KEY_DISTANCE_PENALTY));
        pThis->penaltyRawScore += (float)(extraSkippedIPs * SKIPPED_IP_SCORE_PENALTY) + (extraOmittedKeys * OMITTED_KEY_SCORE_PENALTY) +
                                  (pThis->substituteCount * SUBSTITUTED_KEY_SCORE_PENALTY) + (float)((pThis->transposeCount - pThis->vowelTransposeCount) * TRANSPOSED_KEY_SCORE_PENALTY);
        pThis->penaltyWeightSum = (float)(extraSkippedIPs * SKIPPED_IP_WEIGHT_CREDIT) + (extraOmittedKeys * OMITTED_KEY_WEIGHT_CREDIT) +
                                  (pThis->substituteCount * SUBSTITUTED_KEY_WEIGHT_CREDIT) + (float)((pThis->transposeCount - pThis->vowelTransposeCount) * TRANSPOSED_KEY_WEIGHT_CREDIT);

        dbWord->shiftAnomaly = _FALSE;
#if DEBUG_SHOW_MATCH_TRACE
        if (debugThis)
            pThis->bBreakHere = _TRUE;
#endif

        _SWCSearchDB_ApplyShiftGestures(pThis, dbWord, &shiftPenalty);

        /* If word is shorter than threshold length, add penalty surcharge for any skipped IPs */
        pThis->skipPenaltyWord += shiftPenalty;
        if (dbWord->length <= PENALTY_SURCHARGE_LENGTH2)
        {
            if (pThis->vowelTransposeCount)
            {
                pThis->penaltyRawDist += (pThis->vowelTransposeCount * TRANSPOSED_VOWEL_DISTANCE_PENALTY);
                pThis->penaltyRawScore += (float)(pThis->vowelTransposeCount * TRANSPOSED_VOWEL_SCORE_PENALTY);
                pThis->penaltyWeightSum += (float)(pThis->vowelTransposeCount * TRANSPOSED_VOWEL_WEIGHT_CREDIT);
            }
            if (dbWord->length <= PENALTY_SURCHARGE_LENGTH1)
            {
                pThis->skipPenaltyWord += (SKIPPED_IP_SURCHARGE_FACTOR1 * skipPenaltyIPSum);
                pThis->skipPenaltyWord += (SPELLING_ERROR_SURCHARGE_FACTOR1 * skipPenaltyKeyOmitTranspose);
                pThis->penaltyRawDist += (BYTE4)(long)((PENALTY_DISTANCE_SURCHARGE_FACTOR1 * pThis->penaltyRawDist));
                pThis->penaltyRawScore += (PENALTY_SCORE_SURCHARGE_FACTOR1 * pThis->penaltyRawScore);
                pThis->penaltyWeightSum += (PENALTY_WEIGHT_SURCHARGE_FACTOR1 * pThis->penaltyWeightSum);
            }
            else
            {
                pThis->skipPenaltyWord += (SKIPPED_IP_SURCHARGE_FACTOR2 * skipPenaltyIPSum);
                pThis->skipPenaltyWord += (SPELLING_ERROR_SURCHARGE_FACTOR2 * skipPenaltyKeyOmitTranspose);
                pThis->penaltyRawDist += (BYTE4)(long)((PENALTY_DISTANCE_SURCHARGE_FACTOR2 * pThis->penaltyRawDist));
                pThis->penaltyRawScore += (PENALTY_SCORE_SURCHARGE_FACTOR2 * pThis->penaltyRawScore);
                pThis->penaltyWeightSum += (PENALTY_WEIGHT_SURCHARGE_FACTOR2 * pThis->penaltyWeightSum);
            }
        }
        if (pThis->keySeqLength > 0)
        {
            dbWord->avDistance = (float)pThis->rawDist / (float)pThis->keySeqLength;      /* No repeated keys in keySeqLength for MGD */
            if (dbWord->avDistance < MINIMUM_AV_DISTANCE)       /* Avoid highly improbable (but possible) excessive low scores */
                dbWord->avDistance = MINIMUM_AV_DISTANCE;
            pThis->penaltyAvDistance = (float)(pThis->rawDist + pThis->penaltyRawDist) / (float)(pThis->keySeqLength + pThis->omissionCount);
            if (pThis->penaltyAvDistance < MINIMUM_PENALTY_AV_DISTANCE)        /* Avoid highly improbable (but possible) excessive low scores */
                pThis->penaltyAvDistance = MINIMUM_PENALTY_AV_DISTANCE;
#if DEBUG_SHOW_MATCH_TRACE
            if (debugThis)
            {
                Log(SWLogger_DEBUG, TEXT("SW AD: %0.2f keySeqLen %d, rawDist %d, penRawDist %d, omissionCount %d\n"),
                    dbWord->avDistance, pThis->keySeqLength, pThis->rawDist, pThis->penaltyRawDist, pThis->omissionCount);
            }
#endif
        }
        else    /* Should never happen... */
        {
            /* Shouldn't happen... */
            Log(SWLogger_INFO, SWTEXT("Swype Event: %d \r\n"), 422);
            _SWCSearchDB_FailCandidate(pThis);
            return(-1);
        }
        /*dbWord->keyErrorCount = (pThis->omissionCount + pThis->transposeCount); */

        if (pThis->finalScoringPass)
            pThis->avScore = pThis->rawSlopeScore / pThis->weightSum;
        else
            pThis->avScore = (float)pThis->rawScore / pThis->weightSum;
        if (pThis->avScore < MINIMUM_AV_SCORE)     /* Avoid highly improbable (but possible) excessive low scores */
            pThis->avScore = MINIMUM_AV_SCORE;

        /* May have a significant number of extra IPs due to "scribbled" Double IPs, but assess penalty if reasonable limit exceeded */
        {
            SBYTE2  maxExpectedIPcount = (SBYTE2)(((5 * dbWord->length) >> 2) + (3 * pThis->doubleKeyCount) + 1);            /*lint !e702 */
            if (pThis->m_wIPTableCount > maxExpectedIPcount)
                pThis->skipPenaltyWord += (pThis->m_wIPTableCount - maxExpectedIPcount) * EXCESS_IPS_PENALTY;
        }

        /* Assess penalty if word pattern is much larger than actual path */
        {
            float pathSizePenalty = (float)1.0;
            pThis->wordWidth = pThis->wordMaxX - pThis->wordMinX + 1;        /* Ensure non-zero width and height */
            pThis->wordHeight = pThis->wordMaxY - pThis->wordMinY + 1;
            if ((pThis->wordWidth > 1) || (pThis->wordHeight > 1))        /* If anything other than a single-key word */
            {
                 ET9BOOL pathTooSmall = _TRUE;        /* Only assess higher skipping penalties if word is larger than path */
               /* If word is contained in a single row and path is more or less contained in and centered on the row, */
                /*   then base penalty on X coordinates only */
                if ((pThis->wordHeight == 1) && (pThis->pathHeight <= pThis->m_backend->sScreenGeometry.keyHeight) && (pThis->pathCenterFromRow <= SINGLE_KEY_PATH_ROW_CENTER_MARGIN) &&
                    (absGeo(pThis->wordMinY - pThis->pathCenter) <= SINGLE_KEY_PATH_ROW_CENTER_MARGIN))
                    pathSizePenalty = (float)pThis->wordWidth / (float)pThis->pathWidth;
                else
                    pathSizePenalty = (float)(pThis->wordWidth * pThis->wordHeight) / pThis->pathSize;
                if (pathSizePenalty < (float)1.0)
                {
                    pathSizePenalty = (float)1.0 / pathSizePenalty;
                    pathTooSmall = _FALSE;
                }
                /* TODO: The following two lines seem to be operating on uninitialized memory, and are then reset later on anyway. */
                dbWord->finalScore *= pathSizePenalty;
                dbWord->finalScorePathMatch *= pathSizePenalty;
                if (pathTooSmall)
                {
                    if (pThis->skipPenaltyWord == (float)0.0)
                    {
                        if (pathSizePenalty > MAX_GOOD_PATH_SIZE)
                            pThis->skipPenaltyWord = PATH_SIZE_PENALTY * pathSizePenalty;
                    }
                    else
                        pThis->skipPenaltyWord *= pathSizePenalty;
                }
            }

            dbWord->skipPenalty = pThis->skipPenaltyWord;
            dbWord->omitCount = pThis->omitCount;
            dbWord->omissionCount = pThis->omissionCount;
            {
                SBYTE2 i;
                for (i = 0; i < OMIT_KEYS_MAX; i++)
                {
                    dbWord->omitKeys[i] = pThis->omitKeysActual[i];
                    dbWord->omitCounts[i] = pThis->omitCounts[i];
                }
            }
            dbWord->grossErrors = pThis->skippedIPsWord + pThis->omissionCount - pThis->substituteCount;
            dbWord->skippedIPs = pThis->skippedIPsWord;
            dbWord->avSlopeFactor = pThis->avSlopeFactor;
#if INTERNAL_STATISTICS
            dbWord->pathSizePenalty = pathSizePenalty;
            dbWord->penaltyAvDistance = pThis->penaltyAvDistance;
            dbWord->rawScore = pThis->rawScore;
            dbWord->weightSum = pThis->weightSum;
            dbWord->avScore = pThis->avScore;
            dbWord->transposeCount = pThis->transposeCount;
            /*dbWord->rawSlopeScore = pThis->rawSlopeScore; */
#endif
        }

        if (pThis->penaltyRawScore)
        {
            if (pThis->finalScoringPass)
                pThis->penaltyAvScore = (pThis->rawSlopeScore + pThis->penaltyRawScore) / (pThis->weightSum + pThis->penaltyWeightSum);
            else
                pThis->penaltyAvScore = ((float)pThis->rawScore + pThis->penaltyRawScore) / (pThis->weightSum + pThis->penaltyWeightSum);
        }
        else
            pThis->penaltyAvScore = pThis->avScore;
        if (pThis->penaltyAvScore < MINIMUM_PENALTY_AV_SCORE)      /* Avoid highly improbable (but possible) excessive low scores */
            pThis->penaltyAvScore = MINIMUM_PENALTY_AV_SCORE;

        /* SavedCodeSegments/SearchDB.cpp/3 (History of versions of finalScore calculation) */

        /* SavedCodeSegments/SearchDB.cpp/69 (More recent history of versions of combinedScore calculation) */

        slopeScore = pThis->avScore;             /* Effect of avSlopeFactor already included in calculation of avScore */
        /*dbWord->noPenaltyScore = slopeScore * (dbWord->avDistance + AV_DISTANCE_SCORE_WEIGHT_ADJUSTMENT); */
        dbWord->noPenaltyScore = slopeScore;
        if (!pThis->algNewNoPenaltyScore[searchAlgorithm])
            dbWord->noPenaltyScore *= (dbWord->avDistance + AV_DISTANCE_SCORE_WEIGHT_ADJUSTMENT);

        penaltySlopeScore = pThis->penaltySlopeFactor * pThis->penaltyAvScore;
        penaltyFreqScore = penaltySlopeScore * (pThis->isMGDataBase ? pThis->FreqWeightMGD[dbWord->freqGroup] : pThis->FreqWeight[dbWord->freqGroup]);
        penaltyFreqScore_PathOnly = penaltySlopeScore;
        if (dbWord->recent)
        {
            if (pThis->isMGDataBase)
            {
                if (pThis->algReduceRecencyWeight[searchAlgorithm])
                    penaltyFreqScore *= pThis->RecencyWeightReducedMGD[dbWord->freqGroup];
                else if (pThis->algIncreaseRecencyWeight[searchAlgorithm])
                    penaltyFreqScore *= pThis->RecencyWeightIncreasedMGD[dbWord->freqGroup];
                else
                    penaltyFreqScore *= pThis->RecencyWeightMGD[dbWord->freqGroup];
            }
            else
            {
                if (pThis->algReduceRecencyWeight[searchAlgorithm])
                    penaltyFreqScore *= pThis->RecencyWeightReduced[dbWord->freqGroup];
                else if (pThis->algIncreaseRecencyWeight[searchAlgorithm])
                    penaltyFreqScore *= pThis->RecencyWeightIncreased[dbWord->freqGroup];
                else
                    penaltyFreqScore *= pThis->RecencyWeight[dbWord->freqGroup];
            }
        }
        else
            if (dbWord->freqStem == MAX_FREQ_CLASS)                  /* Give class 7 words at least some benefit even if not yet used */
        {
            if (pThis->algReduceRecencyWeight[searchAlgorithm])
                penaltyFreqScore *= pThis->Class7MinRecencyWeightReduced;
            else if (pThis->algIncreaseRecencyWeight[searchAlgorithm])
                penaltyFreqScore *= pThis->Class7MinRecencyWeightIncreased;
            else
                penaltyFreqScore *= pThis->Class7MinRecencyWeight;
        }
        dbWord->finalScore = penaltyFreqScore * (pThis->penaltyAvDistance + AV_DISTANCE_SCORE_WEIGHT_ADJUSTMENT) *
                                                    ((float)1.0 + pThis->skipPenaltyWord);

        /* For SRT core, get path match score that doesn't factor in frequency data */
        dbWord->finalScorePathMatch = penaltyFreqScore_PathOnly * (pThis->penaltyAvDistance + AV_DISTANCE_SCORE_WEIGHT_ADJUSTMENT) *
                                                    ((float)1.0 + pThis->skipPenaltyWord);

        {
            float pathUsePenalty = (float)1.0;
            if (pThis->finalMatchPosIndex && (pThis->finalMatchPosIndex < pThis->finalRequiredIPPosIndex))
            {
                pathUsePenalty = (float)pThis->finalRequiredIPPosIndex / (float)pThis->finalMatchPosIndex;
                pathUsePenalty *= pathUsePenalty * pathUsePenalty;
            }

            dbWord->finalScore *= pathUsePenalty;
            dbWord->finalScorePathMatch *= pathUsePenalty;

            {
                SBYTE2 matchedIPs = sw_max(1, pThis->m_wIPTableCount - pThis->skippedIPsWord);
                /*float   matchFactor = (float)((pThis->m_wIPTableCount + extraSkippedIPs) * dbWord->length) / (float)(matchedIPs * pThis->keySeqLength);         //lint !e790 */
                if (!pThis->algNewNoPenaltyScore[searchAlgorithm])
                {
                    /* SavedCodeSegments/284 - Previous old NoPenaltyScore calculation */
                    float matchFactor = (float)((pThis->m_wIPTableCount + extraSkippedIPs) * dbWord->length) / (float)(matchedIPs * pThis->keySeqLength);         /*lint !e790 */
                    float adjustedAvDistance = dbWord->avDistance + AV_DISTANCE_SCORE_WEIGHT_ADJUSTMENT;
                    float tweakNPS;
                    SBYTE2 matchedKeys;
                    float scaleNPS;
                    dbWord->noPenaltyScore *= matchFactor * pathUsePenalty * dbWord->avDistance * adjustedAvDistance * dbWord->avSlopeFactor;
                    tweakNPS = dbWord->skipPenalty + (float)1.0;
                    dbWord->noPenaltyScore *= tweakNPS * (float)0.00005;    /* Also scale value of noPenaltyScore for combinedScore calculations */
                    /* If there are fewer matched letters than IPs in path, apply further penalty */
                    matchedKeys = sw_max(1, pThis->keySeqLength + pThis->repeatedKeyCount);
                    if (pThis->m_wIPTableCount > matchedKeys)
                        tweakNPS *= (float)pThis->m_wIPTableCount / (float)matchedKeys;
                    scaleNPS = dbWord->noPenaltyScore * (float)0.005;
                    dbWord->noPenaltyScoreSort = scaleNPS * tweakNPS * tweakNPS;
                }
                else
                {
                    /* NEW... */
                    float adjustedAvDistance = dbWord->avDistance + AV_DISTANCE_SCORE_WEIGHT_ADJUSTMENT;
                    dbWord->noPenaltyScore *= adjustedAvDistance * dbWord->avSlopeFactor;
                    dbWord->noPenaltyScore *= (float)0.03;            /* Also scale value of noPenaltyScore for combinedScore calculations */
                    dbWord->noPenaltyScoreSort = dbWord->noPenaltyScore * (float)0.01;
                }
            }
        }

#if INTERNAL_STATISTICS
        dbWord->penaltyAvScore = pThis->penaltyAvScore;
        dbWord->slopeScore = slopeScore;
#endif

        if (!pThis->algNewCombinedScore[searchAlgorithm])
        {
            dbWord->combinedScore = dbWord->finalScore * dbWord->noPenaltyScoreSort * (float)0.004;
            dbWord->combinedScorePathMatch = dbWord->finalScorePathMatch * dbWord->noPenaltyScoreSort * (float)0.004;
            dbWord->combinedScore *= (dbWord->finalScore + dbWord->noPenaltyScore);
            dbWord->combinedScorePathMatch *= (dbWord->finalScorePathMatch + dbWord->noPenaltyScore);
        }
        else
        {
            /* SavedCodeSegments/285 - History of combinedScore calculation versions */
            float   tweakScore = pThis->skipPenaltyWord + (float)1.0;
            dbWord->combinedScore = dbWord->finalScore * dbWord->noPenaltyScoreSort * tweakScore;
            dbWord->combinedScorePathMatch = dbWord->finalScorePathMatch * dbWord->noPenaltyScoreSort * tweakScore;
        }

        if (pThis->finalScoringPass)
        {
            if ((pThis->omissionCount <= FEW_ENOUGH_KEY_ERRORS) && (pThis->skippedIPsWord <= FEW_ENOUGH_SKIPPED_IPS))
            {
                dbWord->goodWord = FEW_ENOUGH_ERRORS;
                if (dbWord->combinedScore <= pThis->goodEnoughScoreCurrent)
                {
                    dbWord->goodWord = GOOD_ENOUGH;
                    if (dbWord->combinedScore < pThis->bestGoodWordScore)
                        pThis->bestGoodWordScore = dbWord->combinedScore;
                }
            }
            else
                dbWord->goodWord = UNACCEPTABLE_ERRORS;
        }
    }
    else if (!pThis->isCandidate && !pThis->exitLoop)
    {
        // Haven't failed candidate yet. Do it now, so we get any capitalization changes applied.
        _SWCSearchDB_FailCandidate(pThis);
    }

#if DEBUG_LOG_MATCH_TRACE
    if (debugThis)
    {
        _SWCSearchDB_DebugTraceWordMGD(pThis, dbWord, pThis->skipPenaltyWord, pThis->isCandidate, lastKeyScored);
        if (pThis->finalScoringPass)
        {
            if (debugThis1)
            {
                if (dbWord->skipPenalty > (float)0.0)
                    debugThis1 = _TRUE;
                if (dbWord->skipPenalty > (float)0.1)
                    debugThis1 = _TRUE;
                if (dbWord->skipPenalty > (float)0.5)
                    debugThis1 = _TRUE;
                if (!pThis->isCandidate)
                    debugThis1 = _TRUE;
                if ((dbWord->grossErrors > 0) || (dbWord->skippedIPs > 0))
                    debugThis1 = _TRUE;
            }
            if (debugThis2)
            {
                if (dbWord->skipPenalty > (float)0.0)
                    debugThis2 = _TRUE;
                if (!pThis->isCandidate)
                    debugThis2 = _TRUE;
                if ((dbWord->grossErrors > 0) || (dbWord->skippedIPs > 0))
                    debugThis2 = _TRUE;
            }
            if (debugThis3)
            {
                if (dbWord->skipPenalty > (float)0.0)
                    debugThis3 = _TRUE;
                if (!pThis->isCandidate)
                    debugThis3 = _TRUE;
                if ((dbWord->grossErrors > 0) || (dbWord->skippedIPs > 0))
                    debugThis3 = _TRUE;
            }
        }
        else
        {
            if (debugThis1)
            {
                if (dbWord->skipPenalty > (float)0.0)
                    debugThis1 = _TRUE;
                if (dbWord->skipPenalty > (float)0.1)
                    debugThis1 = _TRUE;
                if (dbWord->skipPenalty > (float)0.5)
                    debugThis1 = _TRUE;
                if (!pThis->isCandidate)
                    debugThis1 = _TRUE;
                if ((dbWord->grossErrors > 0) || (dbWord->skippedIPs > 0))
                    debugThis1 = _TRUE;
            }
            if (debugThis2)
            {
                if (dbWord->skipPenalty > (float)0.0)
                    debugThis2 = _TRUE;
                if (!pThis->isCandidate)
                    debugThis2 = _TRUE;
                if ((dbWord->grossErrors > 0) || (dbWord->skippedIPs > 0))
                    debugThis2 = _TRUE;
            }
            if (debugThis3)
            {
                if (dbWord->skipPenalty > (float)0.0)
                    debugThis3 = _TRUE;
                if (!pThis->isCandidate)
                    debugThis3 = _TRUE;
                if ((dbWord->grossErrors > 0) || (dbWord->skippedIPs > 0))
                    debugThis3 = _TRUE;
            }
        }

    }
#endif

    return((pThis->isCandidate) ? 1 : -1);
} /* _SWCSearchDB_ScoreWordFromKeyRepeats() */

/*============================================================================= */
/* Function:    _SWCSearchDB_ClearSearchIPTable() */
/* Parameters:  None */
/* Description: Clear the IP Table data array. */
/*============================================================================= */

void ET9FARCALL _SWCSearchDB_ClearSearchIPTable(_SWCSearchDB *pThis)
{
    pThis->m_wIPTableCount = 0;
    pThis->m_wIPTable2Count = 0;
    pThis->m_wExitIPTableCount = 0;
} /* _SWCSearchDB_ClearSearchIPTable() */



/* SavedCodeSegments/SearchDB.cpp/40 (previous version of SetZ1OperationSetting()) */

void ET9FARCALL _SWCSearchDB_SetZ1OperationSetting(_SWCSearchDB *pThis, int Z1Level)
{
    int     Z1SettingIncrement = (Z1_OPERATION_MAX - Z1Level) / 2;      /* Amount to increase level to point halfway between current level and Z1_OPERATION_MAX */

    pThis->searchPassLimit = 2;          /* Init to number of levels most often used */
    pThis->IPThresholdLevelsSet = _FALSE;

#if TRACK_STATISTICS
    ToggleStatistics(pThis->TrackZ1Stats);
    if (pThis->Z1OperationLevel != pThis->Z1OperationLevelPrevious)
    {
        OutputVersion(_FALSE);
    }
#endif

    pThis->Z1OperationSetting = Z1Level;

    pThis->Z1OperationLevelPrevious = pThis->Z1OperationLevel;
    pThis->Z1OperationLevel = pThis->Z1OperationLevelCurrent = Z1Level;
    pThis->Z1IterationLevels[0] = Z1Level;
    pThis->Z1IterationLevels[2] = Z1_OPERATION_MAX;
    if (Z1Level <= Z1_SETTING_LEVEL_1)          /* Currently Z1_SETTING_LEVEL_1 == 600 */
    {   /* One additional search at a level halfway between the current level and Z1_OPERATION_MAX */
        pThis->Z1IterationLevels[1] = Z1Level + Z1SettingIncrement;
    }
    else if (Z1Level <= Z1_SETTING_LEVEL_2)         /* Currently Z1_SETTING_LEVEL_2 == 800 */
    {   /* One additional search at a level interpolated between a level halfway between the current level */
        /*   and Z1_OPERATION_MAX (at (Z1_SETTING_LEVEL_1 + 1)) to Z1_OPERATION_MAX (at Z1_SETTING_LEVEL_2) */
        float interpolate = (float)(Z1Level - Z1_SETTING_LEVEL_1) / (float)(Z1_SETTING_LEVEL_2 - Z1_SETTING_LEVEL_1);

        Z1SettingIncrement += (int)(interpolate * (float)Z1SettingIncrement);
        pThis->Z1IterationLevels[1] = Z1Level + Z1SettingIncrement;
    }
    else if (Z1Level < Z1_OPERATION_MAX)
    {   /* One additional search at Z1_OPERATION_MAX */
        pThis->Z1IterationLevels[1] = Z1_OPERATION_MAX;
    }
    else
    {   /* One search only (already at Z1_OPERATION_MAX) */
        pThis->searchPassLimit = 1;
        pThis->Z1IterationLevels[1] = Z1_OPERATION_MAX;
    }
    pThis->Z1OperationLevelMax = pThis->Z1IterationLevels[pThis->searchPassLimit - 1];

    /* Set new parameter levels for each search pass iteration */
    _SWCSearchDB_SetZ1Operation(pThis);
    return;
}   /* _SWCSearchDB_SetZ1OperationSetting() */


#define Z1_LEVEL_MAX        7
static const SBYTE2 haltCheckZ1Level[Z1_LEVEL_MAX] =           {     0,    100,   200,    400,    750,    900,    1000 };

/*const float  KPScoreHaltCheckFlushValue[Z1_LEVEL_MAX] = { 200.0,  250.0, 320.0,  400.0,  480.0,  560.0,  650.0 }; */
/*const float  KPScoreHaltCheckFlushValue[Z1_LEVEL_MAX] = { 350.0,  390.0, 440.0,  500.0,  550.0,  600.0,  650.0 }; */
static const float  KPScoreHaltCheckFlushValue[Z1_LEVEL_MAX] = { 450.0,  490.0, 540.0,  600.0,  650.0,  700.0,  750.0 };

/*const float  KPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 250.0,  325.0, 500.0,  1000.0,  1500.0,  2500.0,  3500.0 }; */
/*const float  KPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 250.0,  325.0, 600.0,  1200.0,  1800.0,  2500.0,  3500.0 }; */
/*const float  KPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 400.0,  750.0, 1100.0,  1500.0,  2000.0,  2500.0,  3500.0 }; */
static const float  KPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 400.0,  750.0, 1100.0,  1225.0,  1350.0,  2000.0,  3000.0 };

static const float  KPScoreHaltCheckValue2[Z1_LEVEL_MAX] =     { 1000.0,  1350.0, 1800.0,  2300.0,  2800.0,  3250.0,  5500.0 };

/*const float  SPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 250.0,  325.0, 600.0,  1200.0,  1800.0,  2500.0,  3500.0 }; */
/*const float  SPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 250.0,  325.0, 600.0,  1000.0,  1600.0,  2300.0,  3000.0 }; */
static const float  SPScoreHaltCheckValue[Z1_LEVEL_MAX] =      { 375.0,  450.0, 700.0,  1100.0,  1600.0,  2300.0,  3000.0 };

/*const float  SPScoreHaltCheckValue2[Z1_LEVEL_MAX] =     { 1000.0,  1350.0, 1800.0,  2300.0,  2800.0,  3250.0,  5500.0 }; */
/*const float  SPScoreHaltCheckValue2[Z1_LEVEL_MAX] =     { 500.0,  900.0, 1200.0,  1600.0,  2100.0,  2800.0,  4000.0 }; */
static const float  SPScoreHaltCheckValue2[Z1_LEVEL_MAX] =     { 750.0,  1100.0, 1500.0,  1900.0,  2400.0,  3000.0,  4500.0 };

/*const float  SfxScoreHaltCheckValue[Z1_LEVEL_MAX] =     { 500.0,  650.0, 750.0, 1500.0, 4000.0, 8000.0, 10000.0 }; */
/* Original 93 values: */
/*const float  SfxScoreHaltCheckValue[Z1_LEVEL_MAX] =     { 2250.0, 2750.0, 3500.0, 6500.0, 10000.0, 16000.0, 25000.0 }; */
/*const float  SfxScoreHaltCheckValue[Z1_LEVEL_MAX] =     { 2500.0, 3250.0, 3750.0, 6500.0, 10000.0, 17000.0, 25000.0 }; */
/*const float  SfxScoreHaltCheckValue[Z1_LEVEL_MAX] =     { 4000.0, 4750.0, 6000.0, 7500.0, 10000.0, 17000.0, 25000.0 }; */
static const float  SfxScoreHaltCheckValue[Z1_LEVEL_MAX] =     { 10000.0, 15000.0, 20000.0, 28000.0, 40000.0, 55000.0, 70000.0 };

/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 100.0,  120.0, 200.0,  300.0,  500.0,  600.0,   800.0 }; */
/* Original 93 values: */
/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 400.0,  500.0, 800.0,  1300.0,  2000.0,  2500.0,  3500.0 }; */
/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 500.0,  600.0, 1000.0,  1500.0,  2500.0,  3000.0,  4000.0 }; */
/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 2500.0,  3000.0, 3500.0,  4000.0,  4500.0,  5000.0,  6000.0 }; */
/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 3000.0,  3250.0, 3500.0,  4000.0,  4500.0,  5000.0,  6000.0 }; */
/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 3750.0,  4000.0, 4250.0,  4500.0,  4750.0,  5000.0,  6000.0 }; */
/*const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 4000.0,  4500.0, 5000.0,  6000.0,  7000.0,  8250.0,  9500.0 }; */
static const float  SfxScoreIncludeValue[Z1_LEVEL_MAX] =       { 10000.0, 12500.0, 17000.0, 23000.0, 30000.0, 37000.0, 45000.0 };

/*const SBYTE2 nCandidatesHaltCheckValue[Z1_LEVEL_MAX] =  {   100,    130,   250,    500,    750,    900,    1000 }; */
static const SBYTE2 nCandidatesHaltCheckValue[Z1_LEVEL_MAX] =  {   100,    110,   135,    180,    225,    320,    500 };

/* Original 93 values: */
/*const SBYTE2 SfxErrorsHaltCheckValue[Z1_LEVEL_MAX] =    {     0,      0,     0,      1,      1,      2,       3 }; */
static const SBYTE2 SfxErrorsHaltCheckValue[Z1_LEVEL_MAX] =    {     0,      1,     1,      1,      1,      2,       3 };

static const SBYTE2 SfxErrorsIncludeValue[Z1_LEVEL_MAX] =    {     0,      0,     0,      0,      1,      1,       1 };

static const float SfxPenaltyIncludeValue[Z1_LEVEL_MAX] =     { (float)0.25, (float)0.25, (float)0.25, (float)0.35, (float)0.5, (float)0.75, (float)1.0 };
static const float SfxPenaltyIncludeValueMGD[Z1_LEVEL_MAX] =  { (float)0.51, (float)0.51, (float)0.51, (float)0.65, (float)0.80, (float)1.0, (float)1.25 };

/*const float  SfxScoreAcceptableValue[Z1_LEVEL_MAX] =  { 10000.0, 10000.0, 10500.0, 11000.0, 12000.0, 14500.0, 15000.0 }; */
/* Original 93 values: */
/*const float  SfxScoreAcceptableValue[Z1_LEVEL_MAX] =  { 12000.0, 12000.0, 13000.0, 14000.0, 15000.0, 16000.0, 18000.0 }; */
/*const float  SfxScoreAcceptableValue[Z1_LEVEL_MAX] =  { 15000.0, 15500.0, 16000.0, 16500.0, 17000.0, 18000.0, 19000.0 }; */
/*const float  SfxScoreAcceptableValue[Z1_LEVEL_MAX] =  { 15000.0, 16000.0, 17500.0, 20000.0, 22000.0, 23500.0, 25000.0 }; */
static const float  SfxScoreAcceptableValue[Z1_LEVEL_MAX] =  { 20000.0, 30000.0, 35000.0, 40000.0, 45000.0, 55000.0, 60000.0 };

/*const float  GoodEnoughScoreHaltCheckValue[Z1_LEVEL_MAX] =    { 30000000.0, 25000000.0, 20000000.0, 12500000.0, 7500000.0, 5000000.0, 3750000.0 }; */
/*const float  GoodEnoughScoreHaltCheckValueMGD[Z1_LEVEL_MAX] = { 50000000.0, 40000000.0, 30000000.0, 20000000.0, 15000000.0, 10000000.0, 7500000.0 }; */
/*const float  GoodEnoughScoreHaltCheckValue[Z1_LEVEL_MAX] =    { 5.0e07, 3.75e07, 2.75e07, 2.0e07, 1.25e07, 7.5e06, 5.0e06 }; */
/*const float  GoodEnoughScoreHaltCheckValue[Z1_LEVEL_MAX] =    { 1.0e08, 7.5e07, 5.5e07, 3.5e07, 2.35e07, 1.25e07, 7.5e06 }; */
static const float  GoodEnoughScoreHaltCheckValue[Z1_LEVEL_MAX] =    { 2.0e08, 1.5e08, 1.0e08, 9.0e07, 8.0e07, 6.5e07, 5.0e07 };

static const float SfxPenaltyHaltCheckValue[Z1_LEVEL_MAX] =  { (float)1.0, (float)1.0, (float)1.2, (float)1.5, (float)1.75, (float)1.9, (float)2.0 };
static const float WordPenaltyHaltCheckValue[Z1_LEVEL_MAX] = { (float)1.0, (float)1.0, (float)1.2, (float)1.5, (float)1.75, (float)1.9, (float)2.0 };

#define MGD_INCLUDE_PENALTY_ADJUSTMENT_FACTOR       (float)1.4
#define MGD_SCORE_LEVEL_ADJUSTMENT_FACTOR           (float)0.70
#define MGD_SCORE_LEVEL_ADJUSTMENT_FACTOR_REDUCED1  (float)0.80
#define MGD_SCORE_LEVEL_ADJUSTMENT_FACTOR_REDUCED2  (float)0.90
#define MGD_FLUSH_CHECK_LEVEL_ADJUSTMENT_FACTOR     (float)0.81
#define MGD_CANDIDATES_LIMIT_ADJUSTMENT_FACTOR      (float)0.667

/* Use the *current* Z1 Operation setting level to set parameters affecting the *extent* of the search.  Use */
/*   the *maximum* Z1 Operation setting level (that would be used in the final pass of the current iterated */
/*   search process) to set parameters affecting the matching process for each word.  This means that every */
/*   word is evaluated the same way, no matter which pass it is evaluated in, so that a word scored in an */
/*   earlier pass does not need to be re-scored in a later pass. */
void ET9FARCALL _SWCSearchDB_SetZ1Operation(_SWCSearchDB *pThis)
{
    float   Z1SearchExtentLevel, Z1MatchParamLevel, Z1LevelAdjust;
    SBYTE2  Z1LevelIndex;
    SBYTE2  iterationLevel;

    /* Don't reset time counts if called with no change in current level, or if we are iterating a search */
    pThis->Z1OperationLevelCurrent = pThis->Z1IterationLevels[0];
    pThis->Z1OperationLevelMax = pThis->Z1IterationLevels[pThis->searchPassLimit - 1];
    Z1SearchExtentLevel = (float)pThis->Z1OperationLevelCurrent / (float)Z1_OPERATION_MAX;

    /* Make sure that FreqWeight[]/FreqWeightMGD[] are set to appropriate "generic" values (implied "average" pen speed and IP count) */
    _SWCSearchDB_SetFreqWeights(pThis, pThis->FreqRangeRatio, ALG_ORIG_NEW2, _FALSE);
    _SWCSearchDB_SetFreqWeights(pThis, pThis->FreqRangeRatio, ALG_MGD, _TRUE);

    /* Parameters affecting the *extent* of the search performed */
    for (iterationLevel = 0; iterationLevel < Z1_SEARCH_LEVEL_MAX; iterationLevel++)
    {
        if (pThis->Z1IterationLevels[iterationLevel] <= Z1_OPERATION_MIN)
        {
            pThis->maxKeyErrorCount[iterationLevel] = MAX_KEY_ERROR_COUNT_MIN;
            Z1SearchExtentLevel = 0.0;
        }
        else if (pThis->Z1IterationLevels[iterationLevel] >= Z1_OPERATION_MAX)
        {
            pThis->maxKeyErrorCount[iterationLevel] = MAX_KEY_ERROR_COUNT_MAX;
            Z1SearchExtentLevel = 1.0;
        }
        else
        {
            Z1SearchExtentLevel = (float)pThis->Z1IterationLevels[iterationLevel] / (float)Z1_OPERATION_MAX;
            pThis->maxKeyErrorCount[iterationLevel] = MAX_KEY_ERROR_COUNT_MIN + (SBYTE2)(Z1SearchExtentLevel * (MAX_KEY_ERROR_COUNT_MAX - MAX_KEY_ERROR_COUNT_MIN));
            for (Z1LevelIndex = 0; Z1LevelIndex < Z1_LEVEL_MAX; Z1LevelIndex++)
            {
                if (pThis->Z1IterationLevels[iterationLevel] <= haltCheckZ1Level[Z1LevelIndex])
                    break;
            }
            if (Z1LevelIndex < 1)
                Z1LevelIndex = 1;
            else if (Z1LevelIndex >= Z1_LEVEL_MAX)
                Z1LevelIndex = Z1_LEVEL_MAX - 1;
            Z1LevelAdjust = (float)(pThis->Z1IterationLevels[iterationLevel] - haltCheckZ1Level[Z1LevelIndex - 1]) / (float)(haltCheckZ1Level[Z1LevelIndex] - haltCheckZ1Level[Z1LevelIndex - 1]);
        }
        if (pThis->isMGDataBase && pThis->algReduceMGDScoreThresholds[pThis->CurrentAlgorithm])
        {
        }
    }
    /* Parameters that affect the matching process for each word or suffix scored (in any pass) */
    if (pThis->Z1OperationLevelMax <= Z1_OPERATION_MIN)
    {
        pThis->maxCandidateIPPenaltyBase = MAX_CANDIDATE_IP_PENALTY_MIN;
        pThis->maxCandidateSpellPenalty = MAX_CANDIDATE_SPELL_PENALTY_MIN;
        pThis->maxSuffixCandidatePenalty = MAX_SUFFIX_CANDIDATE_PENALTY_MIN;
        Z1MatchParamLevel = 0.0;
    }
    else if (pThis->Z1OperationLevelMax >= Z1_OPERATION_MAX)
    {
        pThis->maxCandidateIPPenaltyBase = MAX_CANDIDATE_IP_PENALTY_MAX;
        pThis->maxCandidateSpellPenalty = MAX_CANDIDATE_SPELL_PENALTY_MAX;
        pThis->maxSuffixCandidatePenalty = MAX_SUFFIX_CANDIDATE_PENALTY_MAX;
        Z1MatchParamLevel = 1.0;
    }
    else
    {
        Z1MatchParamLevel = (float)pThis->Z1OperationLevelMax / (float)Z1_OPERATION_MAX;
        pThis->maxCandidateIPPenaltyBase = MAX_CANDIDATE_IP_PENALTY_MIN + (Z1MatchParamLevel * (MAX_CANDIDATE_IP_PENALTY_MAX - MAX_CANDIDATE_IP_PENALTY_MIN));
        pThis->maxCandidateSpellPenalty = MAX_CANDIDATE_SPELL_PENALTY_MIN + (Z1MatchParamLevel * (MAX_CANDIDATE_SPELL_PENALTY_MAX - MAX_CANDIDATE_SPELL_PENALTY_MIN));
        pThis->maxSuffixCandidatePenalty = MAX_SUFFIX_CANDIDATE_PENALTY_MIN + (Z1MatchParamLevel * (MAX_SUFFIX_CANDIDATE_PENALTY_MAX - MAX_SUFFIX_CANDIDATE_PENALTY_MIN));
        for (Z1LevelIndex = 0; Z1LevelIndex < Z1_LEVEL_MAX; Z1LevelIndex++)
        {
            if (pThis->Z1OperationLevelMax <= haltCheckZ1Level[Z1LevelIndex])
                break;
        }
        if (Z1LevelIndex < 1)
            Z1LevelIndex = 1;
        else if (Z1LevelIndex >= Z1_LEVEL_MAX)
            Z1LevelIndex = Z1_LEVEL_MAX - 1;
        Z1LevelAdjust = (float)(pThis->Z1OperationLevelMax - haltCheckZ1Level[Z1LevelIndex - 1]) / (float)(haltCheckZ1Level[Z1LevelIndex] - haltCheckZ1Level[Z1LevelIndex - 1]);
    }

    if (pThis->isMGDataBase)
    {
        if (pThis->Z1OperationLevelMax < Z1_OPERATION_VOWEL_TRANSPOSE_LEVEL_MGD)
            pThis->transpositionLevel = NO_TRANSPOSITIONS;
        else if (pThis->Z1OperationLevelMax >= Z1_OPERATION_ANY_TRANSPOSE_LEVEL_MGD)
            pThis->transpositionLevel = ALL_TRANSPOSITIONS;
        else
            pThis->transpositionLevel = VOWELS_ONLY;
    }
    else
    {
        if (pThis->Z1OperationLevelMax < Z1_OPERATION_VOWEL_TRANSPOSE_LEVEL)
            pThis->transpositionLevel = NO_TRANSPOSITIONS;
        else if (pThis->Z1OperationLevelMax >= Z1_OPERATION_ANY_TRANSPOSE_LEVEL)
            pThis->transpositionLevel = ALL_TRANSPOSITIONS;
        else
            pThis->transpositionLevel = VOWELS_ONLY;
    }
    /* SavedCodeSegments/275 - PERFORM_FUTURE_MATCH_CHECK code */
    if (pThis->Z1IterationLevels[0] <= Z1_OPERATION_MIN)
    {
        pThis->goodEnoughScore = GoodEnoughScoreHaltCheckValue[0];
    }
    else if (pThis->Z1IterationLevels[0] >= Z1_OPERATION_MAX)
        pThis->goodEnoughScore = GoodEnoughScoreHaltCheckValue[Z1_LEVEL_MAX - 1];
    else
    {
        for (Z1LevelIndex = 0; Z1LevelIndex < Z1_LEVEL_MAX; Z1LevelIndex++)
        {
            if (pThis->Z1IterationLevels[0] <= haltCheckZ1Level[Z1LevelIndex])
                break;
        }
        if (Z1LevelIndex < 1)
            Z1LevelIndex = 1;
        else if (Z1LevelIndex >= Z1_LEVEL_MAX)
            Z1LevelIndex = Z1_LEVEL_MAX - 1;
        Z1LevelAdjust = (float)(pThis->Z1IterationLevels[0] - haltCheckZ1Level[Z1LevelIndex - 1]) / (float)(haltCheckZ1Level[Z1LevelIndex] - haltCheckZ1Level[Z1LevelIndex - 1]);
        pThis->goodEnoughScore = GoodEnoughScoreHaltCheckValue[Z1LevelIndex - 1] + (Z1LevelAdjust * (GoodEnoughScoreHaltCheckValue[Z1LevelIndex] - GoodEnoughScoreHaltCheckValue[Z1LevelIndex - 1]));
    }
    /* Original 93: */
    /*if ((pThis->CurrentAlgorithm == ALG_ORIG_NEW) || (pThis->CurrentAlgorithm == ALG_MGD)) */
    /*    pThis->goodEnoughScore *= 3.0e-03; */
    if ((pThis->CurrentAlgorithm == ALG_ORIG_NEW2) || (pThis->CurrentAlgorithm == ALG_MGD))
        pThis->goodEnoughScore *= (float)3.0e-02;

    pThis->IPThresholdFactor = IP_THRESHOLD_FACTOR_LEVEL_MIN + (Z1MatchParamLevel * (IP_THRESHOLD_FACTOR_LEVEL_MAX - IP_THRESHOLD_FACTOR_LEVEL_MIN));
    pThis->SegmentThresholdFactor = SEGMENT_THRESHOLD_FACTOR_LEVEL_MIN + (Z1MatchParamLevel * (SEGMENT_THRESHOLD_FACTOR_LEVEL_MAX - SEGMENT_THRESHOLD_FACTOR_LEVEL_MIN));

    if (pThis->m_backend->pIPTable != NULL)
    {
        SWCIPTable_SetIPThresholdLevels(pThis->m_backend->pIPTable, pThis->IPThresholdFactor, pThis->SegmentThresholdFactor);       /* Update thresholds */
        pThis->IPThresholdLevelsSet = _TRUE;
    }
    else
        pThis->IPThresholdLevelsSet = _FALSE;

}   /* _SWCSearchDB_SetZ1Operation() */

    /* SavedCodeSegments/SearchDB.cpp/47 */

SWCIPTableRow * ET9FARCALL _SWCSearchDB_GetExitEntryIP(_SWCSearchDB *pThis, SBYTE2 exitIndex, IPType desiredIPType)
{
    SWCIPTableRow *ipDat;
    SBYTE2 ipIndexx;
    for (ipIndexx = 0; ipIndexx < pThis->m_wExitIPTableCount; ipIndexx++)
    {
        ipDat = pThis->m_aExitIPTable[ipIndexx];
        if (desiredIPType == Exit)
        {
            if ((ipDat->m_IPIndex == exitIndex) && (ipDat->m_IPType == Exit))
                return(ipDat);
        }
        else if (desiredIPType == Entry)
        {
            if ((ipDat->m_exitIndex == exitIndex) && (ipDat->m_IPType == Entry))
                return(ipDat);
        }
    }
    return(NULL);
}

/*============================================================================= */
/* Function:    _SWCSearchDB_CreateSearchIPTable() */
/* Parameters:  None */
/* Description: Copy the IP Table data array to the copy used by the Search */
/*                routines. */
/*============================================================================= */

void ET9FARCALL _SWCSearchDB_CreateSearchIPTable(_SWCSearchDB *pThis, SBYTE2 searchIndex, ALGORITHM_TYPE searchAlgorithm, ET9BOOL firstAlgorithm, ET9BOOL finalAlgorithm)
{
    if (_ET9AWSP_DATA->bPanic) {
        return;
    }
    _ET9ASW_Trace(SWTracer::TT_CSearchDB, (BYTE2)__LINE__, StrToBYTE4((Str)TEXT("SETIPT")));
    if (firstAlgorithm)
    {
        SWCIPTableRow **pIPTable;
        SWCIPTableRow **pIPTable2;
        /* In the API, this clearing is instead done after ScoreWords from et9aspath.cpp. */

        /* Copy Fixed mouse data to local array */
        SWCIPAnalyzer_CopyFixedDataToZ1(pThis->m_backend->pIPAnalyzer);

        /* Clear out local IP Table */
        _SWCSearchDB_ClearSearchIPTable(pThis);         /* Only call when firstCall is true! */

        /* Copy shift gesture data from IPTable to local arrays */
        pThis->m_SearchShiftLocCount = pThis->m_backend->pIPTable->m_ShiftLocCount;
        pThis->m_SearchShiftAll = pThis->m_backend->pIPTable->m_ShiftAll && _ET9AWSP_DATA->pLingInfo->pLingCmnInfo->Base.pWordSymbInfo->Private.bStateCapsGesture;
        pThis->m_SearchFirstLetterShiftGesture =  pThis->m_backend->pIPTable->firstLetterShiftGesture;
        {
            SBYTE2 i;
            for (i = 0; i < pThis->m_SearchShiftLocCount; i++)
            {
                pThis->m_SearchShiftPos[i] = pThis->m_backend->pIPTable->m_ShiftPos[i];
                pThis->m_SearchEntryXPos[i] = pThis->m_backend->pIPTable->m_EntryXPos[i];
                pThis->m_SearchEntryPosIndex[i] = pThis->m_backend->pIPTable->m_EntryPosIndex[i];
                pThis->m_SearchExitXPos[i] = pThis->m_backend->pIPTable->m_ExitXPos[i];
            }
        }
        /* Move IPTable IPs to local array */
        pIPTable = SWCIPTable_GetIPTableArray(pThis->m_backend->pIPTable);
        pIPTable2 = SWCIPTable_GetIPTableArray2(pThis->m_backend->pIPTable);
        pThis->actualIPTableCount = pThis->m_backend->pIPTable->wIPCount;  /* May include Exit and Entry IPs */
        pThis->ipPenUp = NULL;
        /* Add in forward order for reprocessIPTable() call, then reverse order for suffix search */
        /* Filter out all Entry IPs from m_aIPTable; add all Exit/Entry pairs to m_aExitIPTable */
        pThis->ipPenDown = pIPTable[0];
        DebugAssert(pThis->ipPenDown->m_IPType == PenDown);
        SWCIPTableRow_append(__CONTEXT, pThis->m_aIPTable, &pThis->m_wIPTableCount, _SWYPE_MAX_IPS, pThis->ipPenDown);
        {
            SBYTE2 ipIndexx;
            for (ipIndexx = 1; ipIndexx < pThis->actualIPTableCount; ipIndexx++)
            {
                pThis->ipData = pIPTable[ipIndexx];
                if (pThis->ipData->m_IPType != Entry)
                {
                    /* Identify up to MAX_INITIAL_SEGMENTS consecutive initial segment data IPs (first is PenDown, with no segment data) */
                        /* Always include data for the first segment */
                    SWCIPTableRow_append(__CONTEXT, pThis->m_aIPTable, &pThis->m_wIPTableCount, _SWYPE_MAX_IPS, pThis->ipData);
                    if ((pThis->ipData->m_IPType == PenUp) || (pThis->ipData->m_IPType == SoftUp))        /* Path dimensions are saved in PenUp IP */
                    {
                        SBYTE2 pathCenterFromThisRow;
                        pThis->ipPenUp = pThis->ipData;
                        pThis->pathWidth = pThis->ipData->maxX - pThis->ipData->minX;
                        pThis->pathHeight = pThis->ipData->maxY - pThis->ipData->minY;
                        /* Set pathSize to area of rectangle enclosing path */
                        pThis->pathSize = (float)sw_max(1, pThis->pathWidth) * (float)sw_max(1, pThis->pathHeight);
                        /* Find distance of center of gesture from vertical middle of nearest row (to check whether centered on a row or between rows) */
                        pThis->pathCenter = pThis->pathCenterFromRow = (pThis->ipData->maxY + pThis->ipData->minY) / 2;
                        pThis->pathCenterFromRow = (SBYTE2)(4 * pThis->m_backend->sScreenGeometry.keyHeight);
                        {
                            SBYTE2 i;
                            for (i = 0; i < SWDbm_rowCnt(pThis->m_backend->m_pDbm); i++)
                            {
                                pathCenterFromThisRow = (SBYTE2)(absGeo(pThis->pathCenter - pThis->rowCenter[i]));
                                if (pathCenterFromThisRow < pThis->pathCenterFromRow)
                                    pThis->pathCenterFromRow = pathCenterFromThisRow;
                            }
                        }
                    }
                }
                if ((pThis->ipData->m_IPType == Exit) || (pThis->ipData->m_IPType == Entry))      /* Save Exit and Entry IPs for re-processing segment distance calculations */
                {
                    SWCIPTableRow_append(__CONTEXT, pThis->m_aExitIPTable, &pThis->m_wExitIPTableCount, _SWYPE_MAX_EXIT_IPS, pThis->ipData);
                }
            }
        }
        DebugAssert((pThis->ipPenDown != NULL) && (pThis->ipPenUp != NULL));
        pThis->m_ForceShowWCW = pThis->ipPenDown->m_ForceShowWCW;             /* Only force showing of WCW for 1-letter words when multiple DoubleLetter gesture loops performed */
        {
            SBYTE2 ipIndexx;
            for (ipIndexx = 0; ipIndexx < pThis->m_backend->pIPTable->m_wDoubleIPCount; ipIndexx++)
            {
                pThis->ipData = pIPTable2[ipIndexx];
                if (pThis->ipData->m_IPType == DoubleLetter)
                {
                    /*AlwaysAssert(pThis->ipData->m_DoubleIPIndex == (ipIndexx + 1)); */
                    pThis->ipData->m_DoubleIPIndex = (ipIndexx + 1);
                    SWCIPTableRow_append(__CONTEXT, pThis->m_aIPTable2, &pThis->m_wIPTable2Count, _SWYPE_MAX_IPS, pThis->ipData);
                }
                else
                {
                    Log(SWLogger_INFO, SWTEXT("Swype Event: %d \r\n"), 429)
                    /*SWIPTableRow_Destruct(pThis->ipData); */
                    pThis->ipData = NULL;
                }
            }
        }
        pThis->forward = _TRUE;         /* Table is currently in forward-order */

    }

    ET9Assert(pThis->m_wIPTable2Count == pThis->m_backend->pIPTable->m_wDoubleIPCount);

    /* Define frequency weighting factors based on measured pen speed and number of actual inflection points */
    pThis->penSpeedFactor = (float)SWCIPAnalyzer_GetSpeedFactorDW(pThis->m_backend->pIPAnalyzer) / (float)AV_SPEED_FACTOR;
    pThis->ipCountFactor = (float)1.0 + ((float)1.0 / (float)(pThis->m_wIPTableCount + 1));

    {
        float RunTimeFreqRange = (pThis->FreqRangeRatio * pThis->penSpeedFactor * pThis->ipCountFactor);
        _SWCSearchDB_SetFreqWeights(pThis, RunTimeFreqRange, searchAlgorithm, pThis->isMGDataBase);
    }

#if DEBUG_SHOW_WCW_TRACE
    {
        if (!pThis->isMGDataBase)
        {
            {
                Log(SWLogger_DEBUG, TEXT(" \n ==> FreqWeight[] = %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->FreqWeight[0], pThis->FreqWeight[1], pThis->FreqWeight[2], pThis->FreqWeight[3], pThis->FreqWeight[4], pThis->FreqWeight[5], pThis->FreqWeight[6], pThis->FreqWeight[7]);
                if (firstAlgorithm)
                {
                    Log(SWLogger_DEBUG, TEXT(   "     penSpeedFactor = %f    ipCountFactor = %f\n"), pThis->penSpeedFactor, pThis->ipCountFactor);
                }
            }
        }
        else
        {
            if (firstAlgorithm)
            {
                Log(SWLogger_DEBUG, TEXT(" \n ==> FreqWeightMGD[] = %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->FreqWeightMGD[0], pThis->FreqWeightMGD[1], pThis->FreqWeightMGD[2], pThis->FreqWeightMGD[3], pThis->FreqWeightMGD[4], pThis->FreqWeightMGD[5], pThis->FreqWeightMGD[6], pThis->FreqWeightMGD[7]);
                Log(SWLogger_DEBUG, TEXT(" \n ==> FreqWeightMGD[] = %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n"), pThis->FreqWeightMGD[8 + 0], pThis->FreqWeightMGD[8 + 1], pThis->FreqWeightMGD[8 + 2], pThis->FreqWeightMGD[8 + 3], pThis->FreqWeightMGD[8 + 4], pThis->FreqWeightMGD[8 + 5], pThis->FreqWeightMGD[8 + 6]);
                if (firstAlgorithm)
                {
                    Log(SWLogger_DEBUG, TEXT("     penSpeedFactor = %f    ipCountFactor = %f\n"), pThis->penSpeedFactor, pThis->ipCountFactor);
                }
            }
        }
    }
#endif

    /* Re-process IP Table for revised thresholds based on measured pen speed and possibly adjusted Z1OperationLevel */
    /* Re-check distances against updated thresholds (based on stylus speed) */
    _ET9ASW_Trace(SWTracer::TT_CSearchDB, (BYTE2)__LINE__, StrToBYTE4((Str)TEXT("REPROC")));
    SWCIPTable_reProcessIPTable(pThis->m_backend->pIPTable, searchAlgorithm);

    /* Set maxKeyErrorCountActual, etc., for suffix scoring */
    pThis->maxKeyErrorCountCurrent = pThis->maxKeyErrorCount[searchIndex];
    pThis->maxKeyErrorCountActual = sw_max(pThis->maxKeyErrorCountCurrent, 1);

#if (DEBUG_IPT1B || DEBUG_IPT1C1)
    SWCIPTableRow *ipCheck[DEFAULT_WORD_SIZE];
#endif

#if DEBUG_IPT1B
    BYTE2   prevNextDist[DEFAULT_WORD_SIZE][2];
    for (SBYTE2 ipIndexx = 0; (ipIndexx < pThis->m_wIPTableCount) && (ipIndexx < DEFAULT_WORD_SIZE); ipIndexx++)
    {
        ipCheck[ipIndexx] = m_aIPTable[ipIndexx);
        SWFixedData *IPLoc = _SWCSearchDB_GetZ1FixedData(pThis, ipCheck[ipIndexx]->m_IPPosIndex);
        SBYTE2 prevIndex = (SBYTE2)ipCheck[ipIndexx]->m_IPPosIndex - 1;
        if (prevIndex < 0)
            prevIndex = 0;
        SWFixedData *IPLocPrev = _SWCSearchDB_GetZ1FixedData(pThis, prevIndex);
        SBYTE2 nextIndex = (SBYTE2)ipCheck[ipIndexx]->m_IPPosIndex + 1;
        if (nextIndex >= (SBYTE2)pThis->m_pZ1FixedData->size())
            nextIndex = (SBYTE2)(pThis->m_pZ1FixedData->size() - 1);
        SWFixedData *IPLocNext = _SWCSearchDB_GetZ1FixedData(pThis, nextIndex);
        prevNextDist[ipIndexx][0] = IPLoc->m_Point.distance8(IPLocPrev->m_Point);
        prevNextDist[ipIndexx][1] = IPLoc->m_Point.distance8(IPLocNext->m_Point);
        Log(SWLogger_DEBUG, L" IP[%d]: Type: %d ", (ipIndexx + 1), ipCheck[ipIndexx]->m_IPType);
        Log(SWLogger_DEBUG, L" Loc: (%d, %d) Fixed: %d SegLen: %d  Dist: %d  LenRatio: %f  LenFactor: %f  ",
            ipCheck[ipIndexx]->m_IPLocation.x, ipCheck[ipIndexx]->m_IPLocation.y, ipCheck[ipIndexx]->m_IPPosIndex, ipCheck[ipIndexx]->m_SegmentLen8,
            ipCheck[ipIndexx]->m_LineLen8, ipCheck[ipIndexx]->m_fLengthRatio, ipCheck[ipIndexx]->m_fLengthFactor);
        Log(SWLogger_DEBUG, L" Prev: (%d, %d) at %d  Next: (%d, %d) at %d  Fwd:%d Back:%d dIP: %d\n",
            IPLocPrev->m_Point.x, IPLocPrev->m_Point.y, prevNextDist[ipIndexx][0],
            IPLocNext->m_Point.x, IPLocNext->m_Point.y, prevNextDist[ipIndexx][1], ipCheck[ipIndexx]->m_ForwardMultipleCount, ipCheck[ipIndexx]->m_BackwardMultipleCount, ipCheck[ipIndexx]->m_DoubleIPIndex);
    }
#endif

#if DEBUG_IPT1C1
#if COMPARE_ALGORITHMS
    if (finalAlgorithm)
#endif
    {
        for (SBYTE2 ipIndexx = 0; (ipIndexx < pThis->m_wIPTableCount) && (ipIndexx < DEFAULT_WORD_SIZE); ipIndexx++)
        {
            ipCheck[ipIndexx] = m_aIPTable[ipIndexx);
            Log(SWLogger_DEBUG, L" IP[%d]: Type: %d ", (ipIndexx + 1), ipCheck[ipIndexx]->m_IPType);
            Log(SWLogger_DEBUG, L" Loc: (%d, %d) Fixed: %d SegLen: %d  Dist: %d  LenRatio: %f  LenFactor: %f  ",
                ipCheck[ipIndexx]->m_IPLocation.x, ipCheck[ipIndexx]->m_IPLocation.y, ipCheck[ipIndexx]->m_IPPosIndex, ipCheck[ipIndexx]->m_SegmentLen8,
                ipCheck[ipIndexx]->m_LineLen8, ipCheck[ipIndexx]->m_fLengthRatio, ipCheck[ipIndexx]->m_fLengthFactor);
            Log(SWLogger_DEBUG, L" Fwd:%d Back:%d dIP: %d\n",
                ipCheck[ipIndexx]->m_ForwardMultipleCount, ipCheck[ipIndexx]->m_BackwardMultipleCount, ipCheck[ipIndexx]->m_DoubleIPIndex);
        }
        if (pThis->m_wIPTable2Count > 0)
            Log(SWLogger_DEBUG, L" Double IPs:\n  [Idx] Type ( x, y ) {SC}   [gRatio/score]    In/Pos/Out {dIP} (gCnt/In/Out) [exitInd] mrgCnt [segLen/lineLen]  \n");
        for (SBYTE2 ipIndx = 0; ipIndx < pThis->m_wIPTable2Count; ipIndx++)
        {
            ipCheck[ipIndx] = pThis->m_aIPTable2[ipIndx];  /* get IP */
            Log(SWLogger_DEBUG, TEXT(" %d: [%d]   %d   (%d, %d) {%d} [%f/%f] %d/%d/%d  {%d}    (%d/%d(%d)/%d(%d))   [%d]     %d      [%d/%d] \r\n"),
                ipIndx, ipCheck[ipIndx]->m_IPIndex, ipCheck[ipIndx]->m_IPType, ipCheck[ipIndx]->m_IPLocation.x, ipCheck[ipIndx]->m_IPLocation.y,
                ipCheck[ipIndx]->signChangesOK, ipCheck[ipIndx]->gestureRatio, ipCheck[ipIndx]->circleScore,
                ipCheck[ipIndx]->m_FixedIndexIn, ipCheck[ipIndx]->m_IPPosIndex, ipCheck[ipIndx]->m_FixedIndexOut, ipCheck[ipIndx]->m_DoubleIPIndex,
                ipCheck[ipIndx]->gestureIPCount, ipCheck[ipIndx]->gestureIPIndexIn, ipCheck[ipIndx]->gestureIn, ipCheck[ipIndx]->gestureIPIndexOut, ipCheck[ipIndx]->gestureOut,
                ipCheck[ipIndx]->m_exitIndex, ipCheck[ipIndx]->m_MergeCount, ipCheck[ipIndx]->m_SegmentLen8, ipCheck[ipIndx]->m_LineLen8);
        }
        Log(SWLogger_DEBUG, L" \n");
    }
#endif
    if (finalAlgorithm)
    {
        pThis->m_backend->pIPTable->m_wDoubleIPCount = 0;
    }
}    /* _SWCSearchDB_CreateSearchIPTable(void) */

/*============================================================================= */
/* Function:    _SWCSearchDB_AnalyzePathLength() */
/* Parameters:  None */
/* Description: Analyze the upper and lower bound for qualifying */
/*                path lengths. */
/*============================================================================= */

void ET9FARCALL _SWCSearchDB_AnalyzePathLength(_SWCSearchDB *pThis, ALGORITHM_TYPE searchAlgorithm, ET9BOOL finalAlgorithm)
{
    ET9BOOL added, canBeMultiple;
    SBYTE2 ipIndexActual;
    SWCIPTableRow *ipPrev, *ipPrev2, *ipPreExit, *ipExit;
    SWCIPTableRow **pIPTable = SWCIPTable_GetIPTableArray(pThis->m_backend->pIPTable);

    if (_ET9AWSP_DATA->bPanic) {
        return;
    }
    pThis->actualIPTableCount = pThis->m_backend->pIPTable->wIPCount;  /* May include Exit and Entry IPs */
    pThis->m_wIPTableCount = pThis->m_wIPTable2Count = pThis->m_wExitIPTableCount = 0;


    /* Calculate minPath / maxPath to establish range of pathLength groups searched */
    ipPrev = ipPrev2 = ipPreExit = ipExit = pThis->ipData = NULL;
    pThis->minPath = pThis->maxPath = pThis->actualPath = 0;
    pThis->multipleIPPathLen = 0;
    pThis->overshootPathLen = (SBYTE2)OVERSHOOT_PATH_ESTIMATE;         /* Init to allow for some over/undershoot with respect to PenDown location (even though */
    pThis->undershootPathLen = (SBYTE2)UNDERSHOOT_PATH_ESTIMATE;       /*   PenDown is not flagged as CanHaveOvershoot() */
    pThis->m_wRequiredIPTableCount = 0;
    pThis->finalRequiredIPPosIndex = 0;
    for (ipIndexActual = 0; ipIndexActual < pThis->actualIPTableCount; ipIndexActual++)
    {
        ipPrev2 = ipPrev;
        ipPrev = pThis->ipData;
        pThis->ipData = pIPTable[ipIndexActual];
        canBeMultiple = _FALSE;
        if (pThis->ipData->m_IPType != Entry)  /* Copy to current local table */
        {
            SWCIPTableRow_append(__CONTEXT, pThis->m_aIPTable, &pThis->m_wIPTableCount, _SWYPE_MAX_IPS, pThis->ipData);
            /* See if we need to allow for reduction of minPath due to "Scribble" gesture */
            if ((ipPrev != NULL) && (ipPrev->m_ForwardMultipleCount > 0))
            {
                pThis->multipleIPPathLen = (SBYTE2)(pThis->multipleIPPathLen + pThis->ipData->m_SegmentLen8);                     /* Sum up distances as distance8 values; convert before using below */
                /* If this is first Multiple IP segment, add twice its length (for "doubling back") */
                if ((ipPrev2 == NULL) || (ipPrev2->m_ForwardMultipleCount == 0))
                    pThis->multipleIPPathLen = (SBYTE2)(pThis->multipleIPPathLen + pThis->ipData->m_SegmentLen8);
            }
            else if (_SWCSearchDB_CanHaveOvershoot(pThis->ipData))
            {
                pThis->overshootPathLen = (SBYTE2)(pThis->overshootPathLen + OVERSHOOT_PATH_ESTIMATE);
            }
            if (_SWCSearchDB_CanHaveOvershoot(pThis->ipData))
            {
                pThis->undershootPathLen = (SBYTE2)(pThis->undershootPathLen + UNDERSHOOT_PATH_ESTIMATE);
            }
            if (_SWCSearchDB_IsRequiredIP(pThis->ipData))
            {
                pThis->m_wRequiredIPTableCount++;
                pThis->finalRequiredIPPosIndex = pThis->ipData->m_IPPosIndex;
            }
        }
        /* SavedCodeSegments/SearchDB.cpp/10 (SCORING_METHOD_2 code) */
        added = _FALSE;
        if ((pThis->ipData->m_IPType == Exit) && (ipPrev != NULL))
        {
            ipExit = pThis->ipData;
            ipPreExit = ipPrev;
            pThis->maxPath = (BYTE2)(pThis->maxPath + _SWCSearchDB_GetZ1PathLength(pThis, ipPrev->m_FixedIndexOut, pThis->ipData->m_FixedIndexIn));    /*lint !e613 */
            added = _TRUE;
            SWCIPTableRow_append(__CONTEXT, pThis->m_aExitIPTable, &pThis->m_wExitIPTableCount, _SWYPE_MAX_EXIT_IPS, pThis->ipData); /* Save Exit IPs for re-processing segment distance calculations */
        }
        else if (pThis->ipData->m_IPType == Entry)
        {
            if (ipExit != NULL)
            {   /* Add straight-line path length connecting Exit and Entry points along top of keyboard */
                if (ipExit->m_IPLocation.x > pThis->ipData->m_IPLocation.x)
                    pThis->maxPath = (BYTE2)(pThis->maxPath + ipExit->m_IPLocation.x - pThis->ipData->m_IPLocation.x);
                else
                    pThis->maxPath = (BYTE2)(pThis->maxPath + pThis->ipData->m_IPLocation.x - ipExit->m_IPLocation.x);
                ipExit = NULL;
            }
            added = _TRUE;
            SWCIPTableRow_append(__CONTEXT, pThis->m_aExitIPTable, &pThis->m_wExitIPTableCount, _SWYPE_MAX_EXIT_IPS, pThis->ipData); /* Save Entry IPs for re-processing segment distance calculations - must delete when ExitIPTable cleared */
        }
        if (ipPrev != NULL)
        {
            if (ipPrev->m_IPType == Entry)
            {
                if (ipPreExit != NULL)
                {
                    BYTE2 pathSegment = _SWPoint_distance(&ipPreExit->m_IPLocation, &pThis->ipData->m_IPLocation);
                    pThis->actualPath = (BYTE2)(pThis->actualPath + pathSegment);
                    pThis->minPath = (BYTE2)(pThis->minPath + pathSegment);
                    ipPreExit = NULL;
                }
                pThis->maxPath = (BYTE2)(pThis->maxPath + _SWCSearchDB_GetZ1PathLength(pThis, ipPrev->m_FixedIndexOut, pThis->ipData->m_FixedIndexIn));
                added = _TRUE;
            }
            if (!added)
            {
                if (pThis->ipData->m_IPType != SoftUp)
                {
                    pThis->actualPath = (BYTE2)(pThis->actualPath + _SWCSearchDB_GetZ1PathLength(pThis, ipPrev->m_FixedIndexOut, pThis->ipData->m_FixedIndexIn));
                    pThis->minPath = (BYTE2)(pThis->minPath + _SWPoint_distance(&ipPrev->m_IPLocation, &pThis->ipData->m_IPLocation));
                }
                pThis->maxPath = (BYTE2)(pThis->maxPath + _SWCSearchDB_GetZ1PathLength(pThis, ipPrev->m_FixedIndexOut, pThis->ipData->m_FixedIndexIn));
            }
        }
    }
    /* Copied to current local table, so remove from raw table if this is the final algorithm */
    if (finalAlgorithm) {
        pThis->m_backend->pIPTable->wIPCount = 0;
    }

    pThis->minPath = sw_min(pThis->minPath, pThis->actualPath);
    pThis->multipleIPPathLen = (pThis->multipleIPPathLen + 4) >> 3;       /* Convert to distance in screen display coordinates */
    {
        BYTE2 minPathAdjust = pThis->multipleIPPathLen + pThis->overshootPathLen;
        if (minPathAdjust > 0)
        {
            if (pThis->minPath > (2 * minPathAdjust))
                pThis->minPath = (BYTE2)(pThis->minPath - minPathAdjust);
            else
                pThis->minPath = (BYTE2)(pThis->minPath / 2);      /* Reduce minPath without setting to zero */
        }
    }
    if (pThis->algAddUndershootToMaxLen[searchAlgorithm])
        pThis->maxPath = (BYTE2)(pThis->maxPath + pThis->undershootPathLen);
    if (pThis->minPath > pThis->maxPath)          /* CK: Can this ever happen now? Test if this is actually needed... */
    {
        BYTE2 swapVal = pThis->maxPath;
        pThis->maxPath = pThis->minPath;
        pThis->minPath = swapVal;
    }
    pThis->maxPath = sw_max(pThis->maxPath, pThis->actualPath);
    /*DebugAssert(minPathSave == pThis->minPath); */
    /*DebugAssert(maxPathSave == pThis->maxPath); */
    /*DebugAssert(pThis->actualPathSave == pThis->actualPath); */
    /*DebugAssert(multipleIPPathLenSave == pThis->multipleIPPathLen); */
    /*DebugAssert(overshootPathLenSave == pThis->overshootPathLen); */
    /* SavedCodeSegments/SearchDB.cpp/53 */
    /* SavedCodeSegments/SearchDB.cpp/11 (SCORING_METHOD_2 code) */
}    /* void _SWCSearchDB_AnalyzePathLength(void) */

/* eof */
