predictivesearch/PcsAlgorithm/Algorithm2/src/CPcsAlgorithm2MultiSearchHelper.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:15:33 +0300
branchRCL_3
changeset 85 38bb213f60ba
parent 74 6b5524b4f673
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* 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: Supports initial search feature. 
*
*/

// INCLUDES
#include "FindUtilChineseECE.h"
#include "CPcsAlgorithm2MultiSearchHelper.h"
#include "CPcsAlgorithm2Utils.h"
#include "CPcsDefs.h"
#include <collate.h>
#include <biditext.h>

// Compare functions
TBool Compare2(const HBufC& aFirst, const HBufC& aSecond)
    {
    TPtrC t1(aFirst);
    TPtrC t2(aSecond);
    return (t1.Length() > t2.Length());
    }

TBool Compare3(const TDesC& aFirst, const TDesC& aSecond)
    {
    return aFirst == aSecond;
    }

TBool Compare4(const CPsQuery& aFirst, const CPsQuery& aSecond)
    {
    CPsQuery& first = const_cast<CPsQuery&> (aFirst);
    CPsQuery& second = const_cast<CPsQuery&> (aSecond);
    
    return (first.Count() > second.Count());
    }
// ============================== MEMBER FUNCTIONS ============================

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

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

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

    return self;
    }

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

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

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

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

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

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::SearchMultiL
// Initial search feature.
// Flow of steps in initial search is explained below.
// (1) Extract the pool elements corresponding to one of the queries.
// (2) Always the first query is used here.
// (3) Get pool elements from all caches corresponding to the data stores.
// (4) Convert each query to mode specific form.
// (5) Parse each data element.
// (6) Check for every search query atleast one data element matches.
// (7) If NOT ignore the result.
// (8) If so perform an additional check that number of data matches is
//     atleast equal to number of search queries. This will ensure that same
//     data element has not matched for multiple queries.
// (9) Now include the element in the result.
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::SearchMultiL(const CPsSettings& aSettings, 
                                                   RPointerArray<CPsQuery>& aPsQuery,
                                                   TBool isSearchInGroup, 
                                                   RArray<TInt>& aContactsInGroup, 
                                                   RPointerArray<CPsData>& searchResults,
                                                   RPointerArray<CPsPattern>& searchSeqs,
                                                   TInt keyboardMode)
    {
    __LATENCY_MARK ( _L("CPcsAlgorithm2MultiSearchHelper::SearchMultiL") );
    PRINT ( _L("Enter CPcsAlgorithm2MultiSearchHelper::SearchMultiL") );

    // Create CPcsAlgorithm2FilterHelper object to be used for filtering the results
    TSortType sortType = aSettings.GetSortType();
    CPcsAlgorithm2FilterHelper* filterHelper = CPcsAlgorithm2FilterHelper::NewL(sortType);
    RPointerArray<CPcsPoolElement> elements;

    iMultiSearchResultsArr.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 from cache based on first character
    const CPsQueryItem& firstCharItem = aPsQuery[0]->GetItemAtL(0);
    TInt numValue  = keyMap->PoolIdForCharacter( firstCharItem.Character() );
    
    // Get the elements from all the databases
    for (int dsIndex = 0; dsIndex < aDataStores.Count(); dsIndex++)
        {
        RPointerArray<CPsData> *temp = new (ELeave) RPointerArray<CPsData> ();
        iMultiSearchResultsArr.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);

        // Get the supported data fields for this data store
        RArray<TInt> supportedDataFields;
        cache->GetDataFields(supportedDataFields);

        // Get the filtered data fields for this data store    		
        TUint8 filteredDataMatch = FilterDataFieldsL(requiredDataFields, supportedDataFields);

        // Filter the results now
        FilterResultsMultiL(filterHelper, elements, aPsQuery, filteredDataMatch, 
                            isSearchInGroup, aContactsInGroup, keyboardMode);

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

        elements.Reset();
        supportedDataFields.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(iMultiSearchResultsArr, searchResults);
        }
    else
        {
        // Results are already sorted patternbased
        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 < iMultiSearchResultsArr.Count(); i++)
        {
        iMultiSearchResultsArr[i]->Reset();
        delete iMultiSearchResultsArr[i];
        iMultiSearchResultsArr[i] = NULL;
        }

    iMultiSearchResultsArr.Reset();
    delete filterHelper;

    PRINT ( _L("End CPcsAlgorithm2MultiSearchHelper::SearchMultiL") );
    __LATENCY_MARKEND ( _L("CPcsAlgorithm2MultiSearchHelper::SearchMultiL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::SearchInputMultiL
// Function to search match sequences for multi query
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::SearchMatchSeqMultiL(RPointerArray<CPsQuery>& aPsQuery, 
                                                           TDesC& aData, 
                                                           RPointerArray<TDesC>& aMatchSet,
                                                           RArray<TPsMatchLocation>& aMatchLocation)
    {
    PRINT ( _L("Enter CPcsAlgorithm2MultiSearchHelper::SearchMatchSeqMultiL") );
    CleanupResetAndDestroyPushL( aMatchSet );
    CleanupClosePushL( aMatchLocation );
    
    RPointerArray<HBufC> queryList;
    ConvertQueryToListL(aPsQuery, queryList);

    RPointerArray<HBufC> tempqueryList;
    // Remember a temporary copy of query list
    // since we sort the queries
    for (TInt i = 0; i < queryList.Count(); i++)
        {
        tempqueryList.Append(queryList[i]);
        }
    // To hold the match results
    RPointerArray<TDesC> tmpMatchSet;
    TBool isMatch = ETrue;
    TUint32 wordMatches = 0;

    // Sort the query items before we search them
    TLinearOrder<HBufC> rule(Compare2);
    queryList.Sort(rule);

    // Check for each query atleast one data element matches
    // Loop from the last query so that longest match is seen first
    for (TInt queryIndex = queryList.Count() - 1; queryIndex >= 0; queryIndex--)
        {
        TBool queryMatch = EFalse;
        HBufC* tmpQuery = queryList[queryIndex];
        // Get the original query mode corresponding to this query
        TInt modeIndex = tempqueryList.Find(tmpQuery);

        TLex lex(aData);

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

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

        TInt wordIndex = -1;
        // Search thru multiple words
        while ((tmpData.Length() != 0) && (!queryMatch))
            {
            wordIndex++;

            TPtr ptr = tmpQuery->Des();

            // Perform two checks.
            // 1. Ensure that the word is not matched against any previous query
            // 2. If it is the first match to the query
            TBool isWordMatch = EFalse;
            TReal val;
            Math::Pow(val, 2, wordIndex);
            isWordMatch = wordMatches & (TUint) val;

            if (!isWordMatch)
                {
                // Check if no word is matched till now for this query
                if (!queryMatch)
                    {
                    queryMatch = ETrue;
                    //set the word match bit
                    TReal val;
                    Math::Pow(val, 2, wordIndex);
                    wordMatches |= (TUint) val;
                    }

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

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

                // Add the match location to the data structure array
                aMatchLocation.Append(tempLocation);
                }
            }
        // Next word
        tmpData.Set(lex.NextToken());
        beg = lex.Offset() - tmpData.Length(); // start index of next word  


        // No data element matches the query. Ignore this result.
        if (queryMatch == EFalse)
            {
            isMatch = EFalse;
            break;
            }
        }

    // Count the number of bits set
    TInt matchCount = 0;
    matchCount = BitsSet32(wordMatches);

    // If match add the element to the result set
    // Before adding to the result set, check if there is atleast one match per query
    // Number of bits set in word matches is atleast equal to total number of queries.
    if ((isMatch) && (matchCount >= queryList.Count()))
        {

        // Include the match sequences in the final results
        for (int i = 0; i < tmpMatchSet.Count(); i++)
            {
            TIdentityRelation<TDesC> rule(Compare3);
            CleanupStack::PushL(tmpMatchSet[i]);
            if (aMatchSet.Find(tmpMatchSet[i], rule) == KErrNotFound)
                {
                aMatchSet.Append(tmpMatchSet[i]);
                CleanupStack::Pop();
                }
            else
                {
                CleanupStack::PopAndDestroy();
                }
            }

        // Reset tmp match set
        tmpMatchSet.Reset();
        }
    else
        {
        tmpMatchSet.ResetAndDestroy();
        }

    // Free the query list
    queryList.ResetAndDestroy();
    tempqueryList.Reset();
    
    CleanupStack::Pop();
    CleanupStack::Pop( &aMatchSet );

    PRINT ( _L("End CPcsAlgorithm2MultiSearchHelper::SearchMatchSeqMultiL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::ConvertQueryToList
// Converts the multiple search queries to a list
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::ConvertQueryToListL(RPointerArray<CPsQuery>& aSearchQuery, 
                                                          RPointerArray<HBufC>& aQueryList)
    {
    for (int queryIndex = 0; queryIndex < aSearchQuery.Count(); queryIndex++)
        {
        CPsQuery* query = aSearchQuery[queryIndex];

        HBufC* tmpSearchQuery = HBufC::NewL(KPsQueryMaxLen);
        TPtr ptr = tmpSearchQuery->Des();

        if (query->KeyboardModeL() == EItut) // ITU
            {
            keyMap->GetNumericKeyString(query->QueryAsStringLC(), ptr);
            CleanupStack::PopAndDestroy();
            }
        else if (query->KeyboardModeL() == EQwerty) // QWERTY
            {
            ptr = query->QueryAsStringLC();
            ptr.LowerCase();
            CleanupStack::PopAndDestroy();
            }
        else // UNDEFINED
            {
            ExtractQueryL(*query, ptr);
            ptr.LowerCase();
            }
        aQueryList.Append(tmpSearchQuery);
        }
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::ConvertdDataToKeyBoardModeL
// Converts the input data to the key board mode specified by the query
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::ConvertdDataToKeyBoardModeL(CPsQuery* aQuery, 
                                                                  TPtrC aInputData, 
                                                                  TBuf<KPsQueryMaxLen>& aOutputData)
    {
    if (aQuery->KeyboardModeL() == EItut)
        {
        keyMap->GetNumericKeyString(aInputData, aOutputData);
        }
    else if (aQuery->KeyboardModeL() == EQwerty)
        {
        aOutputData = aInputData;
        aOutputData.LowerCase();
        }
    else
        {
        ExtractQueryL(aInputData, *aQuery, aOutputData);
        aOutputData.LowerCase();
        }
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::FilterResultsMultiL
// Subset search function. Refer the above function for more description.
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::FilterResultsMultiL(CPcsAlgorithm2FilterHelper* aAlgorithmFilterHelper, 
                                                          RPointerArray<CPcsPoolElement>& searchSet,
                                                          RPointerArray<CPsQuery>& searchQuery, 
                                                          TUint8 aFilteredDataMatch,
                                                          TBool isSearchInGroup, 
                                                          RArray<TInt>& aContactsInGroup,
                                                          TInt keyboardMode)
    {
    PRINT ( _L("Enter CPcsAlgorithm2MultiSearchHelper::FilterResultsMultiL") );

    // Convert the individual queries to string form
    RPointerArray<CPsQuery> mySearchQuery;

    // Remember a temporary copy of query list
    // Copy the content of searchQuery
    for (TInt i=0; i<searchQuery.Count(); i++)
        {
        CPsQuery* tempQuery = CPsQuery::NewL();
        iAlgorithm->FindUtilECE()->GetPartOfQueryL(*(searchQuery[i]), 0, 
                                                   searchQuery[i]->Count()-1, *tempQuery);
        mySearchQuery.Append(tempQuery);
        }

    // Sort the query items according to the length of each query 
    TLinearOrder<CPsQuery> rule(Compare4);
    mySearchQuery.Sort(rule);

    // To hold the match results
    RPointerArray<TDesC> tmpMatchSet;

    // 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();

        TBool isMatch = ETrue;
        TUint8 wordMatches = 0;

        // Reset iWordMatches to zero 
        ClearWordMatches();

        // Check for each query atleast one data element matches
        // Loop from the last query so that longest match is seen first
        for (TInt queryIndex = mySearchQuery.Count() - 1; queryIndex >= 0; queryIndex--)            
            {
            TBool queryMatch = EFalse;
            CPsQuery* tmpPsQuery = mySearchQuery[queryIndex];

            for (TInt dataIndex = 0; dataIndex < psData->DataElementCount(); dataIndex++)
                {
                // Filter off data fields not required in search
                TReal bitIndex;
                Math::Pow(bitIndex, 2, dataIndex);

                TUint8 filter = (TUint8) bitIndex & aFilteredDataMatch;
                if (filter == 0x0)
                    {
                    // Move to next data
                    continue;
                    }

                TInt wordIndex = -1;

                TLex lex(psData->Data(dataIndex)->Des());

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

                // Search thru multiple words
                while (tmpData.Length() != 0)
                    {
                    wordIndex++;
                    
                    TPtrC queryPtr = tmpPsQuery->QueryAsStringLC();
                    TBool matched = EFalse;
                    
                    if (keyboardMode == EModeUndefined)
                        {
                        matched = iAlgorithm->FindUtilECE()->MatchRefineL(tmpData, *tmpPsQuery);
                        }
                    else if (keyboardMode == EItut)
                        {
                        matched = iAlgorithm->FindUtil()->Interface()->
                                  MatchRefineL(tmpData, queryPtr, ECustomConverter, iAlgorithm);
                        }
                    else // Qwerty
                        {
                        matched = iAlgorithm->FindUtil()->Interface()->MatchRefineL(tmpData, queryPtr);
                        
                        }
                    
                    CleanupStack::PopAndDestroy(); // queryPtr
                    
                    // Compare the data against query
                    if (matched)
                        {
                        psData->SetDataMatch(dataIndex);

                        // Perform two checks.
                        // 1. Ensure that the word is not matched against any previous query
                        // 2. If it is the first match to the query
                        TBool isWordMatch = IsWordMatch(dataIndex, wordIndex);

                        // Check if the current word is not matched to any query
                        if (!isWordMatch)
                            {
                            // Check if no word is matched for this query till now
                            if (!queryMatch)
                                {
                                wordMatches++;
                                queryMatch = ETrue;
                                SetWordMap(dataIndex, wordIndex);
                                }

                            // Extract matched character sequence and fill in temp array
                            TInt len = tmpPsQuery->Count();
                            if (iAlgorithm->FindUtilECE()->IsChineseWord(tmpData))
                                {
                                len = 1;
                                }

                            HBufC* seq = HBufC::NewL(len);
                            *seq = tmpData.Mid(0, len);

                            seq->Des().UpperCase();
                            TIdentityRelation<TDesC> searchRule(Compare3);
                            if (tmpMatchSet.Find(seq, searchRule) == KErrNotFound)
                                {
                                tmpMatchSet.Append(seq);
                                }
                            else
                                {
                                delete seq;
                                seq = NULL;
                                }
                            }
                        }

                    // Next word
                    tmpData.Set(lex.NextToken());
                    }
                }

            // No data element matches the query. Ignore this result.
            if (queryMatch == EFalse)
                {
                isMatch = EFalse;
                break;
                }
            }

        // If match add the element to the result set
        //  And before adding to the result set, check if there is atleast one match per query
        if ((isMatch) && (wordMatches >= mySearchQuery.Count()))
            {
            if (isSearchInGroup)
                {
                if (aContactsInGroup.Find(psData->Id()) != KErrNotFound)
                    {
                    aAlgorithmFilterHelper->AddL(psData, tmpMatchSet);
                    }
                }
            else
                {
                aAlgorithmFilterHelper->AddL(psData, tmpMatchSet);
                }
            }

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

    mySearchQuery.Reset();

    PRINT ( _L("End CPcsAlgorithm2MultiSearchHelper::FilterResultsMultiL") );
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::SetWordMap()
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::SetWordMap(TInt aIndex, TInt aPosition)
    {
    TReal val;
    Math::Pow(val, 2, aPosition);

    iWordMatches[aIndex] |= (TUint8) val;
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::IsWordMatch()
// ----------------------------------------------------------------------------
TBool CPcsAlgorithm2MultiSearchHelper::IsWordMatch(TInt aDataIndex, TInt aWordIndex)
    {
    TReal val;
    Math::Pow(val, 2, aWordIndex);

    return (iWordMatches[aDataIndex] & (TUint8) val);
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::ExtractQueryL()
// Extracts the query as a string. If the mode of query item is ITU numeric
// character is used. Else the character is used.
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::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());
            }
        }
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::ExtractQueryL()
// Converts the input data refering the modes in the query.
// If the mode of query item is ITU numeric character is used. Else the character
// is used.
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::ExtractQueryL(TDesC& aInput, CPsQuery& aQuery, TDes& aOutput)
    {
    TInt len = -1;

    // Always loop thru the lowest length
    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]);
            }
        }
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::BitsSet32
// Helper funtion to count the number of bits set
// ----------------------------------------------------------------------------
TInt CPcsAlgorithm2MultiSearchHelper::BitsSet32(TUint32 aData)
    {
    TInt count = 0;

    for (count = 0; aData; aData &= (aData - 1))
        {
        count++;
        }

    return count;
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::BitsSet32
// Function to reset the iWordMatches
// ----------------------------------------------------------------------------
void CPcsAlgorithm2MultiSearchHelper::ClearWordMatches()
    {
    for (TInt i = 0; i < MAX_DATA_FIELDS; i++)
        iWordMatches[i] = 0;
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::MultiQuery
// Checks if the query object has multiple queries embedded.
// Seperator used is a space.
// Scans through each query character and creates a new query object on a space.
// Consequtive spaces are skipped.
// Returns an array of query objects.
// ----------------------------------------------------------------------------
RPointerArray<CPsQuery> CPcsAlgorithm2MultiSearchHelper::MultiQueryL(CPsQuery& aQuery)
    {
    RPointerArray<CPsQuery> query;

    const TInt textLength = aQuery.Count();

    for (TInt beg = 0; beg < textLength; ++beg)
        {
        // Skip separators before next word	                
        if (!aQuery.GetItemAtL(beg).Character().IsSpace())
            {
            // Scan the end of the word
            TInt end = beg;
            for (; end < textLength && !aQuery.GetItemAtL(end).Character().IsSpace(); ++end)
                {
                }

            // Create a new query object and append
            CPsQuery* newQuery = CPsQuery::NewL();
            for (int i = beg; i < end; i++)
                {
                CPsQueryItem* item = CPsQueryItem::NewL();
                item->SetCharacter(aQuery.GetItemAtL(i).Character());
                item->SetMode(aQuery.GetItemAtL(i).Mode());
                newQuery->AppendL(*item);
                }
            query.Append(newQuery);

            // Scan for next word
            beg = end;
            }
        }

    return query;
    }

// ----------------------------------------------------------------------------
// CPcsAlgorithm2MultiSearchHelper::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 CPcsAlgorithm2MultiSearchHelper::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