predictivesearch/PcsAlgorithm/Algorithm2/src/CPcsAlgorithm2Helper.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 10:12:17 +0200
changeset 0 e686773b3f54
child 7 b3431bff8c19
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Predictive Contact Search Algorithm 1 helper class
*
*/

// INCLUDES
#include <FindUtil.h>
#include "FindUtilChineseECE.h"
#include "CPcsAlgorithm2.h"
#include "CPcsAlgorithm2Helper.h"
#include "CPcsAlgorithm2Utils.h"
#include "CPcsDebug.h"
#include "CPcsCache.h"
#include "CPcsKeyMap.h"
#include "CPsData.h"
#include "CWords.h"
#include "CPsQuery.h"
#include "CPsQueryItem.h"
#include "CPsDataPluginInterface.h"
#include "CPcsPoolElement.h"

// Compare functions
TBool Compare1(const TDesC& aFirst, const TDesC& aSecond)
    {
    return aFirst == aSecond;
    }

TBool Compare2(const TDesC& aFirst, const TDesC& aSecond)
    {
    return CPcsAlgorithm2Utils::MyCompareC(aFirst, aSecond);
    }

// ============================== MEMBER FUNCTIONS ============================

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::NewL
// Two Phase Construction
// ----------------------------------------------------------------------------
CPcsAlgorithm2Helper* CPcsAlgorithm2Helper::NewL(CPcsAlgorithm2* aAlgorithm)
    {
    PRINT ( _L("Enter CPcsAlgorithm2Helper::NewL") );

    CPcsAlgorithm2Helper* self = new (ELeave) CPcsAlgorithm2Helper();
    CleanupStack::PushL(self);
    self->ConstructL(aAlgorithm);
    CleanupStack::Pop(self);

    PRINT ( _L("End CPcsAlgorithm2Helper::NewL") );

    return self;
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::CPcsAlgorithm2Helper
// Two Phase Construction
// ----------------------------------------------------------------------------
CPcsAlgorithm2Helper::CPcsAlgorithm2Helper()
    {
    PRINT ( _L("Enter CPcsAlgorithm2Helper::CPcsAlgorithm2") );
    PRINT ( _L("End CPcsAlgorithm2Helper::CPcsAlgorithm2") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::ConstructL
// Two Phase Construction
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::ConstructL(CPcsAlgorithm2* aAlgorithm)
    {
    PRINT ( _L("Enter CPcsAlgorithm2Helper::ConstructL") );

    iAlgorithm = aAlgorithm;
    keyMap = iAlgorithm->GetKeyMap();

    PRINT ( _L("End CPcsAlgorithm2Helper::ConstructL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::CPcsAlgorithm2Helper
// Destructor
// ----------------------------------------------------------------------------
CPcsAlgorithm2Helper::~CPcsAlgorithm2Helper()
    {
    PRINT ( _L("Enter CPcsAlgorithm2Helper::~CPcsAlgorithm2Helper") );
    iSearchResultsArr.ResetAndDestroy();
    PRINT ( _L("End CPcsAlgorithm2Helper::~CPcsAlgorithm2Helper") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::SearchMixedL
// Search function for input with both ITU-T and QWERTY mode
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::SearchMixedL(const CPsSettings& aSettings,
                                        CPsQuery& aPsQuery, TBool isSearchInGroup,
                                        RArray<TInt>& aContactsInGroup,
                                        RPointerArray<CPsData>& searchResults,
                                        RPointerArray<CPsPattern>& searchSeqs)
    {
    __LATENCY_MARK ( _L("CPcsAlgorithm2Helper::SearchMixedL") );

    PRINT ( _L("Enter CPcsAlgorithm2Helper::SearchMixedL") );

    // Create filtering helper for the required sort type
    TSortType sortType = aSettings.GetSortType();
    CPcsAlgorithm2FilterHelper* filterHelper =
            CPcsAlgorithm2FilterHelper::NewL(sortType);

    // Convert the search condition to numeric key string
    TBuf<KPsQueryMaxLen> numericKeyStr;
    TPtrC queryPtr = aPsQuery.QueryAsStringLC();
    keyMap->GetNumericKeyString(queryPtr, numericKeyStr);
    PRINT2 ( _L("Numeric Key String for %S = %S"), &queryPtr, &numericKeyStr );

    // Reset the result set array for new search
    iSearchResultsArr.ResetAndDestroy();

    // Get the data stores
    RPointerArray<TDesC> aDataStores;
    aSettings.SearchUrisL(aDataStores);

    // Get the required display fields from the client
    RArray<TInt> requiredDataFields;
    aSettings.DisplayFieldsL(requiredDataFields);

    // Search based on first key str
    TInt numValue = keyMap->PoolIdForCharacter(numericKeyStr[0]);

    // Perform search for each required data store
    RPointerArray<CPcsPoolElement> elements;

    for (int dsIndex = 0; dsIndex < aDataStores.Count(); dsIndex++)
        {

        RPointerArray<CPsData> *temp = new (ELeave) RPointerArray<CPsData> ();
        iSearchResultsArr.Append(temp);

        // Get the contents for this data store
        TInt arrayIndex = iAlgorithm->GetCacheIndex(*(aDataStores[dsIndex]));
        if (arrayIndex < 0)
            {
            continue;
            }
        CPcsCache* cache = iAlgorithm->GetCache(arrayIndex);
        cache->GetContactsForKeyL(numValue, elements);

        // Perform filtering
        FilterResultsMixedL(filterHelper, elements, aPsQuery,
                            isSearchInGroup, aContactsInGroup);

        // If alphabetical sorting, get the results for this datastore               
        if (sortType == EAlphabetical)
            {
            filterHelper->GetResults(*(iSearchResultsArr[dsIndex]));
            }

        elements.Reset();
        }

    aDataStores.ResetAndDestroy();
    requiredDataFields.Reset();

    // If alphabetical sorting, merge the result sets of all datastores
    if (sortType == EAlphabetical)
        {
        // Form the complete searchResults array
        CPcsAlgorithm2Utils::FormCompleteSearchResultsL(iSearchResultsArr,
                                                        searchResults);
        }
    else
        {
        // Results are already sorted pattern based
        filterHelper->GetResults(searchResults);
        }

    // Get the sorted match sequence list
    filterHelper->GetPatternsL(searchSeqs);

    PRINT1 ( _L("Number of search results = %d"), searchResults.Count() );

    // Cleanup         
    for (TInt i = 0; i < iSearchResultsArr.Count(); i++)
        {
        iSearchResultsArr[i]->Reset();
        delete iSearchResultsArr[i];
        iSearchResultsArr[i] = NULL;
        }

    iSearchResultsArr.Reset();

    CleanupStack::PopAndDestroy(); // query
    delete filterHelper;

    PRINT ( _L("End CPcsAlgorithm2Helper::SearchMixedL") );

    __LATENCY_MARKEND ( _L("CPcsAlgorithm2Helper::SearchMixedL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::SearchITUL
// Search function for ITU-T style
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::SearchITUL(const CPsSettings& aSettings,
                                      CPsQuery& aPsQuery, TBool isSearchInGroup,
                                      RArray<TInt>& aContactsInGroup,
                                      RPointerArray<CPsData>& searchResults,
                                      RPointerArray<CPsPattern>& searchSeqs)
    {
    __LATENCY_MARK ( _L("CPcsAlgorithm2Helper::SearchITUL") );

    PRINT ( _L("Enter CPcsAlgorithm2Helper::SearchITUL") );

    // Create filtering helper for the required sort type
    TSortType sortType = aSettings.GetSortType();
    CPcsAlgorithm2FilterHelper* filterHelper =
            CPcsAlgorithm2FilterHelper::NewL(sortType);

    // Convert the search condition to numeric key string
    TBuf<KPsQueryMaxLen> numericKeyStr;
    TPtrC queryPtr = aPsQuery.QueryAsStringLC();
    keyMap->GetNumericKeyString(queryPtr, numericKeyStr);
    PRINT2 ( _L("Numeric Key String for %S = %S"), &queryPtr, &numericKeyStr );
    TInt numValue = keyMap->PoolIdForCharacter(numericKeyStr[0]);

    // Reset the result set array for new search
    iSearchResultsArr.ResetAndDestroy();

    // Get the data stores
    RPointerArray<TDesC> aDataStores;
    aSettings.SearchUrisL(aDataStores);

    // Get the required display fields from the client
    RArray<TInt> requiredDataFields;
    aSettings.DisplayFieldsL(requiredDataFields);

    // Perform search for each required data store
    RPointerArray<CPcsPoolElement> elements;

    for (int dsIndex = 0; dsIndex < aDataStores.Count(); dsIndex++)
        {
        RPointerArray<CPsData> *temp = new (ELeave) RPointerArray<CPsData> ();
        iSearchResultsArr.Append(temp);

        // Get the contents for this data store
        TInt arrayIndex = iAlgorithm->GetCacheIndex(*(aDataStores[dsIndex]));
        if (arrayIndex < 0)
            {
            continue;
            }
        CPcsCache* cache = iAlgorithm->GetCache(arrayIndex);
        cache->GetContactsForKeyL(numValue, elements);

        // Perform filtering
        FilterResultsL(filterHelper, elements, numericKeyStr,
                       isSearchInGroup, aContactsInGroup);

        // If alphabetical sorting, get the results for this datastore               
        if (sortType == EAlphabetical)
            {
            filterHelper->GetResults(*(iSearchResultsArr[dsIndex]));
            }

        elements.Reset();
        }

    aDataStores.ResetAndDestroy();
    requiredDataFields.Reset();

    // If alphabetical sorting, merge the result sets of all datastores
    if (sortType == EAlphabetical)
        {
        // Merge the result sets of individual datastores alphabetically
        CPcsAlgorithm2Utils::FormCompleteSearchResultsL(iSearchResultsArr,
                                                        searchResults);
        }
    else
        {
        // Results are already sorted pattern based 
        filterHelper->GetResults(searchResults);
        }

    // Get the sorted match sequence list
    filterHelper->GetPatternsL(searchSeqs);

    PRINT1 ( _L("Number of search results = %d"), searchResults.Count() );

    // Cleanup
    for (TInt i = 0; i < iSearchResultsArr.Count(); i++)
        {
        iSearchResultsArr[i]->Reset();
        delete iSearchResultsArr[i];
        iSearchResultsArr[i] = NULL;
        }
    iSearchResultsArr.Reset();

    CleanupStack::PopAndDestroy(); // query
    delete filterHelper;

    PRINT ( _L("End CPcsAlgorithm2Helper::SearchITUL") );
    __LATENCY_MARKEND ( _L("CPcsAlgorithm2Helper::SearchITUL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::SearchQWERTYL
// Search function for QWERTY style
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::SearchQWERTYL(const CPsSettings& aSettings,
                                         CPsQuery& aPsQuery, TBool isSearchInGroup,
                                         RArray<TInt>& aContactsInGroup,
                                         RPointerArray<CPsData>& searchResults,
                                         RPointerArray<CPsPattern>& searchSeqs)
    {
    __LATENCY_MARK ( _L("CPcsAlgorithm2Helper::SearchQWERTYL") );
    PRINT ( _L("Enter CPcsAlgorithm2Helper::SearchQWERTYL") );

    // te filtering helper for the required sort type
    TSortType sortType = aSettings.GetSortType();
    CPcsAlgorithm2FilterHelper* filterHelper =
            CPcsAlgorithm2FilterHelper::NewL(sortType);

    // Convert the search condition to numeric key string
    TBuf<KPsQueryMaxLen> numericKeyStr;
    TPtrC queryPtr = aPsQuery.QueryAsStringLC();

    TChar queryChar;

    // Handle Chinese word search case: extract the first char of one of its spelling
    // which will be used as search string
    if (iAlgorithm->FindUtilECE()->IsChineseWord(queryPtr))
        {
        RPointerArray<HBufC> spellList;
        if (iAlgorithm->FindUtilECE()->T9ChineseTranslationL(queryPtr[0], spellList))
            {
            queryChar = *(spellList[0]->Ptr());
            }
        else
            {
            queryChar = queryPtr[0];
            }
        spellList.ResetAndDestroy();
        }
    else
        {
        queryChar = queryPtr[0];
        }

    TInt numValue = keyMap->PoolIdForCharacter(queryChar);
    // Reset the result set array for new search
    iSearchResultsArr.ResetAndDestroy();

    // Get the data stores  
    RPointerArray<TDesC> aDataStores;
    aSettings.SearchUrisL(aDataStores);

    // Get the required display fields from the client
    RArray<TInt> requiredDataFields;
    aSettings.DisplayFieldsL(requiredDataFields);

    // Perform search for each of the required data stores
    RPointerArray<CPcsPoolElement> elements;

    for (int dsIndex = 0; dsIndex < aDataStores.Count(); dsIndex++)
        {

        RPointerArray<CPsData> *temp = new (ELeave) RPointerArray<CPsData> ();
        iSearchResultsArr.Append(temp);

        // Get the contents for this data store
        TInt arrayIndex = iAlgorithm->GetCacheIndex(*(aDataStores[dsIndex]));
        if (arrayIndex < 0)
            {
            continue;
            }
        CPcsCache* cache = iAlgorithm->GetCache(arrayIndex);
        cache->GetContactsForKeyL(numValue, elements);

        // Perform filtering
        FilterResultsQwertyL(filterHelper, elements, queryPtr,
                             isSearchInGroup, aContactsInGroup);

        // If alphabetical sorting, get the results for this datastore               
        if (sortType == EAlphabetical)
            {
            filterHelper->GetResults(*(iSearchResultsArr[dsIndex]));
            }

        elements.Reset();
        }
    aDataStores.ResetAndDestroy();
    requiredDataFields.Reset();

    // If alphabetical sorting, merge the result sets of all datastores
    if (sortType == EAlphabetical)
        {
        // Form the complete searchResults array
        CPcsAlgorithm2Utils::FormCompleteSearchResultsL(iSearchResultsArr,
                                                        searchResults);
        }
    else
        {
        // Results are already sorted pattern based
        filterHelper->GetResults(searchResults);
        }

    // Get the sorted match sequence list
    filterHelper->GetPatternsL(searchSeqs);

    PRINT1 ( _L("Number of search results = %d"), searchResults.Count() );

    // Cleanup             
    for (TInt i = 0; i < iSearchResultsArr.Count(); i++)
        {
        iSearchResultsArr[i]->Reset();
        delete iSearchResultsArr[i];
        iSearchResultsArr[i] = NULL;
        }
    iSearchResultsArr.Reset();

    CleanupStack::PopAndDestroy(); // query
    delete filterHelper;

    PRINT ( _L("End CPcsAlgorithm2Helper::SearchQWERTYL") );
    __LATENCY_MARKEND ( _L("CPcsAlgorithm2Helper::SearchQWERTYL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::SearchMatchSeqL
// Funciton to search matching sequences in the input text
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::SearchMatchSeqL(HBufC* /*aQuery*/, TDesC& aData,
                                           RPointerArray<TDesC>& /*aMatchSet*/, 
                                           CPsQuery& /*aPsQuery*/,
                                           RArray<TPsMatchLocation>& aMatchLocation)
    {
    PRINT ( _L("Enter CPcsAlgorithm2Helper::SearchMatchSeqL") );

    // Convert the data into words		     
    TLex lex(aData);

    // First word
    TPtrC token = lex.NextToken();

    TInt beg = lex.Offset() - token.Length(); // start index of match sequence

    // Search thru multiple words
    while (token.Length() != 0)
        {
        TPsMatchLocation tempLocation;

        // check for directionality of the text
        TBool found(EFalse);
        TBidiText::TDirectionality dir = TBidiText::TextDirectionality(token, &found);

        tempLocation.index = beg;
        tempLocation.length = 0;
        tempLocation.direction = dir;

        // Add the match location to the data structure array
        aMatchLocation.Append(tempLocation);

        // Next word
        token.Set(lex.NextToken());
        beg = lex.Offset() - token.Length(); // start index of next word
        }

    PRINT ( _L("End CPcsAlgorithm2Helper::SearchMatchSeqL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2::FilterResultsL
// Subset search function
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::FilterResultsL(CPcsAlgorithm2FilterHelper* aAlgorithmFilterHelper, 
                                          RPointerArray<CPcsPoolElement>& searchSet, 
                                          const TDesC& searchQuery,
                                          TBool isSearchInGroup, 
                                          RArray<TInt>& aContactsInGroup)
    {
    __LATENCY_MARK ( _L("CPcsAlgorithm2Helper::FilterResultsL") );
    PRINT ( _L("Enter CPcsAlgorithm2Helper::FilterResultsL") );

    // Convert the search condition to numeric key string
    TBuf<KPsQueryMaxLen> tmpSearchQuery;
    keyMap->GetNumericKeyString(searchQuery, tmpSearchQuery);
    
    //Holds the first char of first name of a contact
    TBuf<10> firstChar;   

    PRINT2 ( _L("Numeric Key String for %S = %S"), &searchQuery, &tmpSearchQuery );

    // Parse thru each search set elements and filter the results
    for (int index = 0; index < searchSet.Count(); index++)
        {
        CPcsPoolElement* poolElement = static_cast<CPcsPoolElement*> (searchSet[index]);
        CPsData* psData = poolElement->GetPsData();
        psData->ClearDataMatches();
        RPointerArray<TDesC> tempMatchSeq;

        // Search thru multiple words
        TBuf<KBufferMaxLen> token;
        TBuf<KBufferMaxLen> firstName;
        TBuf<KBufferMaxLen> lastName;
        lastName.Append(psData->Data(iAlgorithm->GetLastNameIndex())->Des());
        firstName.Append(psData->Data(iAlgorithm->GetFirstNameIndex())->Des());

        CFindUtilChineseECE* pFindUtilEce = iAlgorithm->FindUtilECE();
        TBool matched  = 0;

        // If has Chinese word and the first name doesn't start with Chinese character, then should add a space
        // before the first name, otherwise intitial letter searching will not function
        if( pFindUtilEce->IsChineseWord(lastName) || pFindUtilEce->IsChineseWord(firstName))
            {
            token.Append(lastName);
            if (firstName.Length())
                {
                firstChar.Zero();
                firstChar.Append(firstName[0]);
                if (!pFindUtilEce->IsChineseWord(firstChar) )
                    {
                    token.Append(KSpace);
                    }
                token.Append(firstName);
                }

            if (token.Length() != 0)
                {
                matched = iAlgorithm->FindUtil()->Interface()->
                    MatchRefineL(token, tmpSearchQuery, ECustomConverter, iAlgorithm);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            }
        else
            {
            // If contact name only has western word, then should send 
            // "first name","last name" and "last name + first name" to FindUtil to do the search
            const TInt lastnameLen = lastName.Length();
            const TInt firstnameLen = firstName.Length();
            if(lastnameLen)
                {
                matched = iAlgorithm->FindUtil()->Interface()->
                    MatchRefineL(lastName, tmpSearchQuery, ECustomConverter, iAlgorithm);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    }
                }

            if(!matched && firstnameLen)
                {
                matched = iAlgorithm->FindUtil()->Interface()->
                    MatchRefineL(firstName, tmpSearchQuery, ECustomConverter, iAlgorithm);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            
            token.Append(lastName);
            token.Append(firstName);
            if (!matched && lastnameLen && firstnameLen)
                {
                matched = iAlgorithm->FindUtil()->Interface()->
                    MatchRefineL(token, tmpSearchQuery, ECustomConverter, iAlgorithm);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            }

        if (matched)
            {
            // Extract matched character sequence, don't need to be accurate for Chinese variant
            const TInt len = 1;  
            HBufC* seq = HBufC::NewLC(len);
            *seq = token.Mid(0, len);
            seq->Des().UpperCase();

            TIdentityRelation<TDesC> rule(Compare1);
            if (tempMatchSeq.Find(seq, rule) == KErrNotFound)
                {
                tempMatchSeq.Append(seq);
                CleanupStack::Pop();
                }
            else
                {
                CleanupStack::PopAndDestroy();
                }
                

            // Add the result        
            if (isSearchInGroup)
                {
                if (aContactsInGroup.Find(psData->Id()) != KErrNotFound)
                    {
                    aAlgorithmFilterHelper->AddL(psData, tempMatchSeq);
                    }
                }
            else
                {
                aAlgorithmFilterHelper->AddL(psData, tempMatchSeq);
                }
            }

        // Cleanup the match sequence array as 
        // they are stored in pattern details structure
        tempMatchSeq.ResetAndDestroy();
        }

    PRINT ( _L("End CPcsAlgorithm2Helper::FilterResultsL") );
    __LATENCY_MARKEND ( _L("CPcsAlgorithm2Helper::FilterResultsL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::FilterResultsQwertyL
// Subset search function 
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::FilterResultsQwertyL(CPcsAlgorithm2FilterHelper* aAlgorithmFilterHelper, 
                                                RPointerArray<CPcsPoolElement>& searchSet, 
                                                const TDesC& searchQuery,TBool isSearchInGroup, 
                                                RArray<TInt>& aContactsInGroup)
    {
    PRINT ( _L("Enter CPcsAlgorithm2::FilterResultsQwertyL") );

    TBuf<50> tmpSearchQuery = searchQuery;
    tmpSearchQuery.LowerCase();
    
    //Holds the first char of first name of a contact
    TBuf<10> firstChar;

    // Parse thru each search set elements and filter the results    
    for (int index = 0; index < searchSet.Count(); index++)
        {
        CPcsPoolElement* poolElement = static_cast<CPcsPoolElement*> (searchSet[index]);
        CPsData* psData = poolElement->GetPsData();
        psData->ClearDataMatches();
        RPointerArray<TDesC> tempMatchSeq;

        // Parse thru each data and filter the results
        TBuf<KBufferMaxLen> token;
        TBuf<KBufferMaxLen> firstName;
        TBuf<KBufferMaxLen> lastName;
        lastName.Append(psData->Data(iAlgorithm->GetLastNameIndex())->Des());
        firstName.Append(psData->Data(iAlgorithm->GetFirstNameIndex())->Des());

        CFindUtilChineseECE* pFindUtilEce = iAlgorithm->FindUtilECE();
        TBool matched  = 0;

        // If has Chinese word and the first name doesn't start with Chinese character, then should add a space
        // before the first name, otherwise intitial letter searching will not function
        if( pFindUtilEce->IsChineseWord(lastName) || pFindUtilEce->IsChineseWord(firstName))
            {
            token.Append(lastName);
            if (firstName.Length())
                {
                firstChar.Zero();
                firstChar.Append(firstName[0]);
                if (!pFindUtilEce->IsChineseWord(firstChar) )
                    {
                    token.Append(KSpace);
                    }
                token.Append(firstName);
                }

            if (token.Length() != 0)
                {
                matched = iAlgorithm->FindUtil()->Interface()->MatchRefineL(token, tmpSearchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            }
        else
            {
            // If contact name only has western word, then should send 
            // "first name","last name" and "last name + first name" to FindUtil to do the search
            const TInt lastnameLen = lastName.Length();
            const TInt firstnameLen = firstName.Length();
            if(lastnameLen)
                {
                matched = iAlgorithm->FindUtil()->Interface()->MatchRefineL(lastName, tmpSearchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    }
                }

            if(!matched && firstnameLen)
                {
                matched = iAlgorithm->FindUtil()->Interface()->MatchRefineL(firstName, tmpSearchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            
            token.Append(lastName);
            token.Append(firstName);
            if (!matched && lastnameLen && firstnameLen)
                {
                matched = iAlgorithm->FindUtil()->Interface()->MatchRefineL(token, tmpSearchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            }
        
        if (matched)
            {
            // Extract matched character sequence, don't need to be accurate for Chinese variant
            const TInt len = 1;
            HBufC* seq = HBufC::NewLC(len);
            *seq = token.Mid(0, len);
            seq->Des().UpperCase();

            TIdentityRelation<TDesC> rule(Compare1);
            if (tempMatchSeq.Find(seq, rule) == KErrNotFound)
                {
                tempMatchSeq.Append(seq);
                CleanupStack::Pop();
                }
            else
                {
                CleanupStack::PopAndDestroy();
                }
            
            // Add the result
            if (isSearchInGroup)
                {
                if (aContactsInGroup.Find(psData->Id()) != KErrNotFound)
                    {
                    aAlgorithmFilterHelper->AddL(psData, tempMatchSeq);
                    }
                }
            else
                {
                aAlgorithmFilterHelper->AddL(psData, tempMatchSeq);
                }
            }

        // Cleanup the match sequence array as 
        // they are stored in pattern details structure
        tempMatchSeq.ResetAndDestroy();
        }

    PRINT ( _L("End CPcsAlgorithm2Helper::FilterResultsQwertyL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::FilterResultsMixedL
// Subset search function
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::FilterResultsMixedL(CPcsAlgorithm2FilterHelper* aAlgorithmFilterHelper, 
                                               RPointerArray<CPcsPoolElement>& searchSet, 
                                               CPsQuery& searchQuery, TBool isSearchInGroup,
                                               RArray<TInt>& aContactsInGroup)
    {
    PRINT ( _L("Enter CPcsAlgorithm2::FilterResultsMixedL") );

    // Convert the search query to alpha numeric string
    TBuf<50> tmpSearchQuery;
    ExtractQueryL(searchQuery, tmpSearchQuery);
    tmpSearchQuery.LowerCase();
    TBuf<10> firstChar;

    // Parse thru each search set elements and filter the results    
    for (int index = 0; index < searchSet.Count(); index++)
        {
        CPcsPoolElement* poolElement = static_cast<CPcsPoolElement*> (searchSet[index]);
        CPsData* psData = poolElement->GetPsData();
        psData->ClearDataMatches();
        RPointerArray<TDesC> tempMatchSeq;

        // Parse thru each data and filter the results
        TBuf<255> token;
        TBuf<KBufferMaxLen> firstName;
        TBuf<KBufferMaxLen> lastName;
        lastName.Append(psData->Data(iAlgorithm->GetLastNameIndex())->Des());
        firstName.Append(psData->Data(iAlgorithm->GetFirstNameIndex())->Des());

        CFindUtilChineseECE* pFindUtilEce = iAlgorithm->FindUtilECE();
        TBool matched  = 0;

        // If has Chinese word and the first name doesn't start with Chinese character, then should add a space
        // before the first name, otherwise intitial letter searching will not function
        if( pFindUtilEce->IsChineseWord(lastName) || pFindUtilEce->IsChineseWord(firstName))
            {
            token.Append(lastName);
            if (firstName.Length())
                {
                firstChar.Zero();
                firstChar.Append(firstName[0]);
                if (!pFindUtilEce->IsChineseWord(firstChar) )
                    {
                    token.Append(KSpace);
                    }
                token.Append(firstName);
                }

            if (token.Length() != 0)
                {
                matched = pFindUtilEce->MatchRefineL(token, searchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            }
        else
            {
            // If contact name only has western word, then should send 
            // "first name","last name" and "last name + first name" to FindUtil to do the search
            const TInt lastnameLen = lastName.Length();
            const TInt firstnameLen = firstName.Length();
            if(lastnameLen)
                {
                matched = pFindUtilEce->MatchRefineL(lastName, searchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    }
                }

            if(!matched && firstnameLen)
                {
                matched = pFindUtilEce->MatchRefineL(firstName, searchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            
            token.Append(lastName);
            token.Append(firstName);
            if (!matched && lastnameLen && firstnameLen)
                {
                matched = pFindUtilEce->MatchRefineL(token, searchQuery);

                if (matched)
                    {
                    psData->SetDataMatch(iAlgorithm->GetLastNameIndex());
                    psData->SetDataMatch(iAlgorithm->GetFirstNameIndex());
                    }
                }
            }

        if (matched)
            {
            // Extract matched character sequence, don't need to be accurate for Chinese variant
            const TInt len = 1;       
        
            HBufC* seq = HBufC::NewLC(len);
            *seq = token.Mid(0, len);
            seq->Des().UpperCase();

            TIdentityRelation<TDesC> rule(Compare1);
            if (tempMatchSeq.Find(seq, rule) == KErrNotFound)
                {
                tempMatchSeq.Append(seq);
                CleanupStack::Pop();
                }
            else
                {
                CleanupStack::PopAndDestroy();
                }
            
            // Add the result
            if (isSearchInGroup)
                {
                if (aContactsInGroup.Find(psData->Id()) != KErrNotFound)
                    {
                    aAlgorithmFilterHelper->AddL(psData, tempMatchSeq);
                    }
                }
            else
                {
                aAlgorithmFilterHelper->AddL(psData, tempMatchSeq);
                }
            }

        // Cleanup the match sequence array as 
        // they are stored in pattern details structure
        tempMatchSeq.ResetAndDestroy();
        }

    PRINT ( _L("End CPcsAlgorithm2Helper::FilterResultsMixedL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::SortSearchSeqsL()
// 
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::SortSearchSeqsL(RPointerArray<TDesC>& aSearchSeqs)
    {
    // Sort the search seqs
    TLinearOrder<TDesC> rule(Compare2);
    aSearchSeqs.Sort(rule);
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::ExtractQueryL()
// Required for mixed mode search.
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::ExtractQueryL(CPsQuery& aQuery, TDes& aOutput)
    {
    for (int i = 0; i < aQuery.Count(); i++)
        {
        if (aQuery.GetItemAtL(i).Mode() == EItut)
            {
            TBuf<KPsQueryMaxLen> outBuf;
            keyMap->GetNumericKeyString(aQuery.QueryAsStringLC(), outBuf);
            aOutput.Append(outBuf[i]);
            CleanupStack::PopAndDestroy();
            }
        else
            {
            aOutput.Append(aQuery.GetItemAtL(i).Character());
            }
        }
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::ExtractQueryL()
// Required for mixed mode search.
// ----------------------------------------------------------------------------
void CPcsAlgorithm2Helper::ExtractQueryL(TDesC& aInput, CPsQuery& aQuery, TDes& aOutput)
    {
    TInt len = -1;

    if (aInput.Length() > aQuery.Count())
        {
        len = aQuery.Count();
        }
    else
        {
        len = aInput.Length();
        }

    for (int i = 0; i < len; i++)
        {
        if (aQuery.GetItemAtL(i).Mode() == EItut)
            {
            TBuf<KPsQueryMaxLen> outBuf;
            keyMap->GetNumericKeyString(aInput, outBuf);
            aOutput.Append(outBuf[i]);
            }
        else
            {
            aOutput.Append(aInput[i]);
            }
        }
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2Helper::FilterDataFieldsL()
// Constructs a bit pattern using the required/supported data fields
// For example, 6, 4 and 27 are supported fields <-- 00000111
//              6 and 4 are required fields      <-- 00000011
// Bit pattern returned is 00000011.
// ----------------------------------------------------------------------------
TUint8 CPcsAlgorithm2Helper::FilterDataFieldsL(RArray<TInt>& aRequiredDataFields, 
                                               RArray<TInt>& aSupportedDataFields)
    {
    TUint8 filteredMatch = 0x0;

    for (int i = 0; i < aSupportedDataFields.Count(); i++)
        {
        for (int j = 0; j < aRequiredDataFields.Count(); j++)
            {
            if (aSupportedDataFields[i] == aRequiredDataFields[j])
                {
                TReal val;
                Math::Pow(val, 2, i);

                filteredMatch |= (TUint8) val;
                }
            }
        }

    return filteredMatch;
    }

// End of file