phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkPhoneNumberMatchStrategy.cpp
branchRCL_3
changeset 20 f4a778e096c2
child 21 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkPhoneNumberMatchStrategy.cpp	Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1212 @@
+/*
+* Copyright (c) 2005-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:  A high level class for matching phone numbers from stores.
+*
+*/
+
+
+// INCLUDES
+#include <CVPbkPhoneNumberMatchStrategy.h>
+
+#include <CVPbkContactManager.h>
+#include <CVPbkContactLinkArray.h>
+#include <MVPbkContactOperation.h>
+#include <MVPbkContactStoreList.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkContactStoreProperties.h>
+#include <MVPbkContactLink.h>
+#include <MVPbkStoreContact.h>
+#include <MVPbkSingleContactOperationObserver.h>
+#include <RLocalizedResourceFile.h>
+#include <VPbkDataCaging.hrh>
+#include <VPbkEng.rsg>
+#include <VPbkFieldTypeSelectors.rsg>
+#include <CVPbkFieldTypeSelector.h>
+#include <CVPbkFieldFilter.h>
+#include <barsread.h>
+#include <MVPbkContactFieldTextData.h>
+#include <CVPbkContactStoreUriArray.h>
+#include <centralrepository.h>
+#include <VPbkStoreUriLiterals.h>
+
+#include "CVPbkPhoneNumberSequentialMatchStrategy.h"
+#include "CVPbkPhoneNumberParallelMatchStrategy.h"
+#include "CVPbkETelCntConverter.h"
+
+#include <cntdb.h>
+#include <ecom/ecom.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <cntphonenumparser.h>
+#endif
+// CONSTANTS
+// Unnamed namespace for local definitions
+namespace {
+// --------------------------------------------------------------------------
+// Phonebook Central Repository UIDs
+// Copied from sf\app\contacts\phonebookui\Phonebook2\inc\Phonebook2InternalCRKeys.h
+// --------------------------------------------------------------------------
+//
+const TUint32 KCRUidPhonebookStoreConfiguration             = 0x1020727f;
+const TUint32 KPhonebookCurrentConfigurationPartialKey      = 0x00000100;
+const TUint32 KPhonebookCurrentConfigurationMask            = 0xffffff00;
+
+const TInt KInitialStoreUriSize = 22; // length of KVPbkDefaultCntDbURI
+const TInt KMagicNumber = -1;
+} // namespace
+
+NONSHARABLE_CLASS(CVPbkPhoneNumberMatchStrategyImpl) :
+        public CActive,
+        public MVPbkContactFindObserver,
+        public MVPbkSingleContactOperationObserver
+    {
+    public: // Construction
+        static CVPbkPhoneNumberMatchStrategyImpl* NewL(
+                CVPbkPhoneNumberMatchStrategy& aParent,
+                const CVPbkPhoneNumberMatchStrategy::TConfig& aConfig,
+                CVPbkContactManager& aContactManager,
+                MVPbkContactFindObserver& aObserver);
+        ~CVPbkPhoneNumberMatchStrategyImpl();
+
+    public: // Interface
+        void MatchL(const TDesC& aPhoneNumber);
+        TInt MaxMatchDigits() const;
+        TArray<MVPbkContactStore*> StoresToMatch() const;
+        TBool IsSimStore( const MVPbkContactStore& aStore );
+        
+    private: // From CActive
+        void RunL();
+        void DoCancel();
+        TInt RunError(TInt aError);
+
+    private: // From MVPbkContactFindObserver
+        void FindCompleteL(MVPbkContactLinkArray* aResults);
+        void FindFailed(TInt aError);
+
+    private: // From MVPbkSingleContactOperationObserver
+        void VPbkSingleContactOperationComplete(
+                MVPbkContactOperationBase& aOperation,
+                MVPbkStoreContact* aContact);
+        void VPbkSingleContactOperationFailed(
+                MVPbkContactOperationBase& aOperation,
+                TInt aError);
+   
+    private:
+        /// Phone number types
+        enum TNumberType { ENotInitialized, EUnknown, EDigit, EPlus, EOneZero, ETwoZeros };
+        
+    private: // Implementation
+        CVPbkPhoneNumberMatchStrategyImpl(CVPbkPhoneNumberMatchStrategy& aParent);
+        void ConstructL(
+                const CVPbkPhoneNumberMatchStrategy::TConfig& aConfig,
+                CVPbkContactManager& aContactManager,
+                MVPbkContactFindObserver& aObserver);
+
+        /**
+         * Searches for a store that has given URI from the list of
+         * stores that the contact manager has.
+         * @param aUriPtr URI of the store to search for.
+         * @return The store with aUriPtr, or NULL if store was not found.
+         */
+        MVPbkContactStore* FindStoreL(
+                const TVPbkContactStoreUriPtr& aUriPtr);
+
+        /**
+         * Issues new request to be handled in RunL.
+         */
+        void IssueRequest();
+
+        MVPbkContactLink* IsValidResultLC(MVPbkStoreContact* aContact);
+
+        /**
+         * Creates name tokens array
+         * @param aContact which is checking, RPointerArray reference
+         */
+        void CreateNameTokensArrayL( MVPbkStoreContact* aContact, RPointerArray <HBufC>& aNameTokensArray );
+        
+        /**
+         * Check if contact already exists in results array
+         * @param aContact which is checking
+         * @return True if contact exist or if array was empty.
+         */
+        TBool CheckContactDuplicationL( MVPbkStoreContact* aContact );
+        
+        /**
+         * Gets contact's field value
+         * @param aContact to get field's value from
+         * @param aFieldType: EVPbkVersitNameN for Last Name 
+         * EVPbkVersitNameFN for First Name
+         * @return Pointer descriptor with field's value.
+         */
+        TPtrC NameFieldValueL( MVPbkStoreContact* aContact, TVPbkFieldTypeName aFieldType );
+        
+        TBool ValidateBestMatchingRulesL( const TDesC& aNumber );
+        TBool CheckBestMatchingRules( const TDesC& aNumberA, TNumberType aNumberAType,
+                const TDesC& aNumberB, TNumberType aNumberBType  );
+        TInt FormatAndCheckNumberType( TDes& aNumber );
+        
+        /**
+         * Reads current store configuration from central repositiry
+         * @return Array of stores or NULL if error during reading form cenrep.
+        */
+        CVPbkContactStoreUriArray* GetCurrentStoreConfigurationL();
+        
+        /**
+         * If there is in the results at least one contact
+         * from currently used stores in Phonebook2 it removes from results 
+         * contacts from other stores
+        */
+        void RefineDuplicatedNumbersL();
+        
+        /**
+         * Load number parser plugin.
+        */
+        void LoadNumberParserPluginL();
+        
+    private: // Data
+        CVPbkPhoneNumberMatchStrategy& iParent;
+        /// Ref: The contact manager instance to be used for searching.
+        CVPbkContactManager* iContactManager;
+        /// Ref: Observer for the searching process.
+        MVPbkContactFindObserver* iObserver;
+        /// Own: The find operation that is currently ongoing.
+        MVPbkContactOperationBase* iOperation;
+        /// Maximum number of matched digits.
+        TInt iMaxMatchDigits;
+        /// Flags to configure matching process, @see TVPbkPhoneNumberMatchFlags
+        TUint32 iMatchFlags;
+
+        /// Own: Array of stores that are used in matching.
+        RPointerArray<MVPbkContactStore> iStoresToMatch;
+        /// Own: Phone number that is being matched.
+        HBufC* iPhoneNumber;
+        /// Own: Intermediate results of the matching process.
+        CVPbkContactLinkArray* iWorkingResults;
+        /// Own: Final results of the matching process.
+        CVPbkContactLinkArray* iResults;
+        /// iWorkingResults index of current contact retrieval
+        TInt iCurrentContact;
+
+        /// Own: Currently retrieved contact
+        MVPbkStoreContact* iStoreContact;
+        /// Own: Field type selector
+        CVPbkFieldTypeSelector* iFieldTypeSelector;
+        /// Own: A filtered and sorted collection of Virtual Phonebook contact fields.
+        CVPbkFieldFilter* iFieldFilter;
+
+        /// Active object states
+        enum TState { EMatch, ERemoveDuplicates, ERefineSearch, EComplete };
+        /// Active object current state
+        TState iState;
+        
+        /// Own: First Name field type selector
+        CVPbkFieldTypeSelector* iFirstNameSelector;
+        /// Own: Last Name field type selector
+        CVPbkFieldTypeSelector* iLastNameSelector;
+        /// Own: Array of tokens gotten from first and last name fields of first matched contact
+        RPointerArray <HBufC> iNameTokensArray;
+        /// Own: Array of tokens gotten from first and last name fields of contact
+        RPointerArray <HBufC> iTempNameTokensArray;
+        /// Indicates if all contact in iResult are the same
+        TBool iDoubledContacts;
+        /// type of iPhoneNumber
+        TNumberType iPhoneNumberType;
+        // Own: parser
+        CContactPhoneNumberParser* iParser;
+    };
+
+CVPbkPhoneNumberMatchStrategyImpl::CVPbkPhoneNumberMatchStrategyImpl(
+        CVPbkPhoneNumberMatchStrategy& aParent) :
+    CActive(CActive::EPriorityIdle),
+    iParent(aParent)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+inline void CVPbkPhoneNumberMatchStrategyImpl::ConstructL(
+        const CVPbkPhoneNumberMatchStrategy::TConfig& aConfig,
+        CVPbkContactManager& aContactManager,
+        MVPbkContactFindObserver& aObserver)
+    {
+    iContactManager = &aContactManager;
+    iObserver = &aObserver;
+
+    iMaxMatchDigits = aConfig.iMaxMatchDigits;
+    iMatchFlags = aConfig.iMatchFlags;
+
+    const TInt uriCount = aConfig.iUriPriorities.Count();
+    for (TInt i = 0; i < uriCount; ++i)
+        {
+        MVPbkContactStore* store = FindStoreL(aConfig.iUriPriorities[i]);
+        if (store)
+            {
+            iStoresToMatch.AppendL(store);
+            }
+        }
+
+    VPbkEngUtils::RLocalizedResourceFile resFile;
+    resFile.OpenLC(iContactManager->FsSession(),
+                   KVPbkRomFileDrive,
+                   KDC_RESOURCE_FILES_DIR,
+                   KVPbkFieldTypeSelectorsResFileName);
+    HBufC8* selectorBuf = resFile.AllocReadLC(R_VPBK_PHONE_NUMBER_SELECTOR);
+    TResourceReader resReader;
+    resReader.SetBuffer(selectorBuf);
+
+    iFieldTypeSelector = CVPbkFieldTypeSelector::NewL(resReader, iContactManager->FieldTypes());
+
+    CleanupStack::PopAndDestroy( selectorBuf );
+    
+    if ( iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkDuplicatedContactsMatchFlag )
+    	{ 
+	    HBufC8* firstNameSelectorBuf = resFile.AllocReadLC( R_VPBK_FIRST_NAME_SELECTOR );
+	    resReader.SetBuffer( firstNameSelectorBuf );
+	    iFirstNameSelector = CVPbkFieldTypeSelector::NewL( resReader, iContactManager->FieldTypes() );
+	    CleanupStack::PopAndDestroy( firstNameSelectorBuf );
+	
+	    HBufC8* lastNameSelectorBuf = resFile.AllocReadLC( R_VPBK_LAST_NAME_SELECTOR );
+	    resReader.SetBuffer( lastNameSelectorBuf );
+	    iLastNameSelector = CVPbkFieldTypeSelector::NewL( resReader, iContactManager->FieldTypes() );
+	    CleanupStack::PopAndDestroy( lastNameSelectorBuf );
+    	}
+
+    CleanupStack::PopAndDestroy( &resFile );
+    
+    LoadNumberParserPluginL();
+    }
+
+CVPbkPhoneNumberMatchStrategyImpl* CVPbkPhoneNumberMatchStrategyImpl::NewL(
+        CVPbkPhoneNumberMatchStrategy& aParent,
+        const CVPbkPhoneNumberMatchStrategy::TConfig& aConfig,
+        CVPbkContactManager& aContactManager,
+        MVPbkContactFindObserver& aObserver)
+    {
+    CVPbkPhoneNumberMatchStrategyImpl* self =
+            new(ELeave) CVPbkPhoneNumberMatchStrategyImpl(aParent);
+    CleanupStack::PushL(self);
+    self->ConstructL(aConfig, aContactManager, aObserver);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CVPbkPhoneNumberMatchStrategyImpl::~CVPbkPhoneNumberMatchStrategyImpl()
+    {
+    Cancel();
+    
+    delete iFieldFilter;
+    delete iFieldTypeSelector;
+    delete iWorkingResults;
+    delete iResults;
+    delete iStoreContact;
+    delete iPhoneNumber;
+    delete iOperation;
+    delete iFirstNameSelector;
+    delete iLastNameSelector;
+    iNameTokensArray.ResetAndDestroy();
+    iTempNameTokensArray.ResetAndDestroy();
+    iStoresToMatch.Close();
+    delete iParser;
+    REComSession::FinalClose();
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::MatchL(const TDesC& aPhoneNumber)
+    {
+    HBufC* phoneNumber = aPhoneNumber.AllocL();
+    delete iPhoneNumber;
+    iPhoneNumber = phoneNumber;
+    iPhoneNumberType = ENotInitialized;
+    
+    if ( iWorkingResults )
+        {
+        iWorkingResults->ResetAndDestroy();
+        }                
+    if ( iResults )
+        {
+        iResults->ResetAndDestroy();
+        }                
+    iCurrentContact = KMagicNumber;
+    
+    if ( iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkDuplicatedContactsMatchFlag )
+    	{
+    	iDoubledContacts = ETrue;
+    	}
+    else
+    	{
+    	iDoubledContacts = EFalse;
+    	}
+    iState = EMatch;
+    IssueRequest();
+    }
+
+
+void CVPbkPhoneNumberMatchStrategyImpl::IssueRequest()
+    {
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete(status, KErrNone);
+    SetActive();
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::RunL()
+    {
+    switch (iState)
+        {
+        case EMatch:
+            {
+            MVPbkContactOperation* operation = iParent.CreateFindOperationLC(*iPhoneNumber);
+            if (operation)
+                {
+                operation->StartL();
+                CleanupStack::Pop(); // operation
+                delete iOperation;
+                iOperation = operation;
+                }
+            else
+                {
+                // all needed operations are done if any
+                iState = ERemoveDuplicates;
+                IssueRequest();
+                }
+            break;
+            }
+        case ERemoveDuplicates:
+            {
+            const TInt count = iWorkingResults ? iWorkingResults->Count() : 0;
+            CVPbkContactLinkArray* results = CVPbkContactLinkArray::NewLC();
+            for (TInt i = 0; i < count; ++i)
+                {
+                MVPbkContactLink* link = iWorkingResults->At(i).CloneLC();
+                if (results->Find(*link) == KErrNotFound)
+                    {
+                    results->AppendL(link);
+                    CleanupStack::Pop(); // link
+                    }
+                else
+                    {
+                    CleanupStack::PopAndDestroy(); // link
+                    }
+                }
+            CleanupStack::Pop(results);
+            delete iWorkingResults;
+            iWorkingResults = results;
+            iState = ERefineSearch;
+            iCurrentContact = 0;
+            IssueRequest();
+            break;
+            }
+        case ERefineSearch:
+            {
+            if (!iResults)
+                {
+                iResults = CVPbkContactLinkArray::NewL();
+                }
+            
+            MVPbkContactLink* result = IsValidResultLC( iStoreContact );
+            if ( result )
+                {
+                iResults->AppendL( result );
+                CleanupStack::Pop(); // MVPbkContactLink
+                
+                if ( iDoubledContacts )
+                    {
+                    iDoubledContacts = CheckContactDuplicationL( iStoreContact );
+                    }
+                }
+
+            delete iStoreContact;
+            iStoreContact = NULL;
+                
+            const TInt count = iWorkingResults ? iWorkingResults->Count() : 0;
+            if (iCurrentContact < count &&                 
+                !( iResults->Count() > 0 && 
+                        (iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkStopOnFirstMatchFlag)))
+                {
+                const MVPbkContactLink& link = iWorkingResults->At(iCurrentContact);
+                delete iOperation;
+                iOperation = NULL;
+                iOperation = iContactManager->RetrieveContactL(link, *this);
+                ++iCurrentContact;
+                }
+            else
+                {
+                iState = EComplete;
+                IssueRequest();
+                }
+            break;
+            }
+        case EComplete:
+            {
+            iNameTokensArray.ResetAndDestroy();
+            iTempNameTokensArray.ResetAndDestroy();
+            if ( iDoubledContacts && iResults->Count() )
+                {
+                CVPbkContactLinkArray* results = CVPbkContactLinkArray::NewLC();
+                MVPbkContactLink* link = iResults->At(0).CloneLC(); // first element
+                results->AppendL( link );
+                CleanupStack::Pop( 2, results ); // results, link
+                delete iResults;
+                iResults = results;
+                }
+
+            if ( iResults->Count() > 1 )
+                {
+                RefineDuplicatedNumbersL();
+                }
+
+            CVPbkContactLinkArray* results = iResults;
+            iResults = NULL;            
+            iObserver->FindCompleteL( results );
+            break;
+            }
+        default:
+            {
+            // This case should not be possible
+            User::Leave( KErrArgument );
+            break;
+            }
+        }
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::DoCancel()
+    {
+    }
+
+TInt CVPbkPhoneNumberMatchStrategyImpl::RunError(TInt aError)
+    {
+    iObserver->FindFailed(aError);
+    return KErrNone;
+    }
+
+inline MVPbkContactStore* CVPbkPhoneNumberMatchStrategyImpl::FindStoreL(
+        const TVPbkContactStoreUriPtr& aUriPtr)
+    {
+    const TInt storeCount = iContactManager->ContactStoresL().Count();
+    for (TInt i = 0; i < storeCount; ++i)
+        {
+        MVPbkContactStore& store = iContactManager->ContactStoresL().At(i);
+        if (store.StoreProperties().Uri().Compare(
+                    aUriPtr,
+                    TVPbkContactStoreUriPtr::EContactStoreUriAllComponents) == 0)
+            {
+            return &store;
+            }
+        }
+    return NULL;
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::FindCompleteL(MVPbkContactLinkArray* aResults)
+    {
+    // This function called by operation which is created in 
+    // iParent.CreateFindOperationLC
+    if (aResults)
+        {
+        CleanupDeletePushL( aResults ); // Take ownership
+        
+        if (!iWorkingResults)
+            {
+            iWorkingResults = CVPbkContactLinkArray::NewL();
+            }
+        const TInt count = aResults->Count();
+        for (TInt i = 0; i < count; ++i)
+            {
+            MVPbkContactLink* link = aResults->At(i).CloneLC();
+            iWorkingResults->AppendL(link);
+            CleanupStack::Pop(); // link
+            }
+
+        CleanupStack::PopAndDestroy(); // aResults
+        }
+    IssueRequest();
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::FindFailed(TInt aError)
+    {
+    iObserver->FindFailed(aError);
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::VPbkSingleContactOperationComplete(
+        MVPbkContactOperationBase& aOperation,
+        MVPbkStoreContact* aContact)
+    {
+    if (iOperation == &aOperation)
+        {
+        delete iOperation;
+        iOperation = NULL;
+
+        iStoreContact = aContact;
+        IssueRequest();
+        }
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::VPbkSingleContactOperationFailed(
+        MVPbkContactOperationBase& aOperation,
+        TInt aError)
+    {
+    if (iOperation == &aOperation)
+        {
+        delete iOperation;
+        iOperation = NULL;
+
+        iObserver->FindFailed(aError);
+        }
+    }
+
+TInt CVPbkPhoneNumberMatchStrategyImpl::MaxMatchDigits() const
+    {
+    return iMaxMatchDigits;
+    }
+
+TArray<MVPbkContactStore*> CVPbkPhoneNumberMatchStrategyImpl::StoresToMatch() const
+    {
+    return iStoresToMatch.Array();
+    }
+
+MVPbkContactLink* CVPbkPhoneNumberMatchStrategyImpl::IsValidResultLC(
+        MVPbkStoreContact* aContact)
+    {
+    MVPbkContactLink* result = NULL;
+
+    if (!(iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkExactMatchFlag)
+            && !(iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkBestMatchingFlag))
+        {
+        // If exact match is not needed we will accept the contact as valid
+        // if it is not NULL
+        if ( aContact )
+            {
+            result = aContact->CreateLinkLC();
+            }        
+        }
+    else if (aContact)
+        {
+        TPtrC matchedNumber = iPhoneNumber->Des().
+                Right(Min(iPhoneNumber->Length(), iMaxMatchDigits));
+
+        CVPbkFieldFilter::TConfig config(aContact->Fields(), iFieldTypeSelector);
+        if (!iFieldFilter)
+            {
+            iFieldFilter = CVPbkFieldFilter::NewL(config);
+            }
+        else
+            {
+            iFieldFilter->ResetL(config);
+            }
+        const TInt count = iFieldFilter->FieldCount();
+        for (TInt i = 0; i < count; ++i)
+            {
+            MVPbkContactFieldData& data = iFieldFilter->FieldAt(i).FieldData();
+            if (data.DataType() == EVPbkFieldStorageTypeText)
+                {
+                const TDesC& dataText = MVPbkContactFieldTextData::Cast(data).Text();
+                if (iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkExactMatchFlag)
+                    {
+                    TPtrC dataTextPtr = dataText.Right(Min(dataText.Length(), iMaxMatchDigits));
+                    if (dataTextPtr == matchedNumber)
+                        {
+                        result = iFieldFilter->FieldAt(i).CreateLinkLC();
+                        break;
+                        }
+                    }
+                else if (iMatchFlags & CVPbkPhoneNumberMatchStrategy::EVPbkBestMatchingFlag
+                            && ValidateBestMatchingRulesL(dataText))
+                    {
+                    result = aContact->CreateLinkLC();
+                    break;
+                    }
+                }
+            }
+        }
+    return result;
+    }
+
+TBool CVPbkPhoneNumberMatchStrategyImpl::CheckContactDuplicationL(
+        MVPbkStoreContact* aContact )
+    {
+
+    if ( !aContact )
+        {
+        return ETrue;
+        }
+    
+    if ( aContact && iCurrentContact == 1 )
+        {
+        CreateNameTokensArrayL( aContact, iNameTokensArray );
+        return ETrue;
+        }
+    else 
+        {
+        iTempNameTokensArray.ResetAndDestroy();
+        CreateNameTokensArrayL( aContact, iTempNameTokensArray );
+        TInt count = iNameTokensArray.Count();
+        if ( iNameTokensArray.Count() != iTempNameTokensArray.Count() )
+        	{
+        	return EFalse;
+        	}
+        else
+        	{
+        	TInt result = 0;
+        	for ( TInt i = 0; i < count; i++ )
+        		{
+        		HBufC* token = iNameTokensArray[i];
+        		TInt tempCount = iTempNameTokensArray.Count();
+            	for ( TInt j = 0; j < tempCount; j++ )
+            		{
+            		result = token->Compare( *( iTempNameTokensArray[j] ) );
+                	if ( !result )
+                		{
+                		HBufC* removedToken = iTempNameTokensArray[j];
+                		iTempNameTokensArray.Remove( j );
+                		delete removedToken;
+                		break;
+                		}
+            		}
+            	if ( result )
+            		{
+            		return EFalse;
+            		}
+        		}
+        	}
+        return ETrue;
+        }
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::CreateNameTokensArrayL( MVPbkStoreContact* aContact,
+										RPointerArray <HBufC>& aNameTokensArray )
+	{
+    TPtrC firstName = NameFieldValueL( aContact, EVPbkVersitNameFN );
+    TLex lexer;
+    lexer.Assign( firstName );
+    
+    TPtrC ptr;
+    TInt len = 0;
+    while( ETrue )
+        {
+        ptr.Set( lexer.NextToken() );
+        
+        len = ptr.Length();
+        if ( len )
+            {
+            HBufC* token = ptr.AllocLC();
+            aNameTokensArray.AppendL( token );
+            CleanupStack::Pop( token );
+            }
+        else
+            {
+            break;
+            }
+        } 
+
+    TPtrC lastName = NameFieldValueL( aContact, EVPbkVersitNameN );
+
+    lexer.Assign( lastName );
+    
+    len = 0;
+    while( ETrue )
+        {
+        ptr.Set( lexer.NextToken() );
+        
+        len = ptr.Length();
+        if ( len )
+            {
+            HBufC* token = ptr.AllocLC();
+            aNameTokensArray.AppendL( token );
+            CleanupStack::Pop( token );
+            }
+        else
+            {
+            break;
+            }
+        }
+	}
+
+TPtrC CVPbkPhoneNumberMatchStrategyImpl::NameFieldValueL( 
+        MVPbkStoreContact* aContact, TVPbkFieldTypeName aFieldType )
+    {
+    if ( aContact )
+        {
+        CVPbkFieldFilter::TConfig config( aContact->Fields() );
+        if ( aFieldType == EVPbkVersitNameFN )
+            {
+            config.iFieldSelector = iFirstNameSelector;
+            }
+        else if ( aFieldType == EVPbkVersitNameN )
+            {
+            config.iFieldSelector = iLastNameSelector;
+            }
+        else
+            {
+            return KNullDesC();
+            }
+        
+        if (!iFieldFilter)
+            {
+            iFieldFilter = CVPbkFieldFilter::NewL(config);
+            }
+        else
+            {
+            iFieldFilter->ResetL(config);
+            }
+        const TInt count = iFieldFilter->FieldCount();
+        for (TInt i = 0; i < count; ++i)
+            {
+            MVPbkContactFieldData& data = iFieldFilter->FieldAt(i).FieldData();
+            if (data.DataType() == EVPbkFieldStorageTypeText)
+                {
+                return  MVPbkContactFieldTextData::Cast(data).Text();
+                }
+            }
+        return KNullDesC();
+        }
+    else
+        {
+        return KNullDesC();
+        }
+    }
+
+// Removes non-digit chars except plus form the beginning
+// Checks if number matches to one of defined types
+//
+TInt CVPbkPhoneNumberMatchStrategyImpl::FormatAndCheckNumberType( TDes& aNumber )
+    {
+    _LIT( KOneZeroPattern, "0*" );
+    _LIT( KTwoZerosPattern, "00*" );
+    _LIT( KPlusPattern, "+*" );
+    _LIT( KPlusString, "+" );
+    const TChar KPlus = TChar('+');
+    const TChar KZero = TChar('0');
+    const TChar KAsterisk = TChar('*');
+    const TChar KHash = TChar('#');
+    
+    HBufC* numberBuf = HBufC::NewL( aNumber.Length() );
+    TPtr number = numberBuf->Des();
+    if ( iParser )
+        {
+        iParser->ExtractRawNumber( aNumber, number );
+        }
+    TInt pos = aNumber.Find( number );
+    
+    if ( pos > 0 && aNumber[pos-1] == KPlus )
+        {
+        number.Insert( 0, KPlusString );
+        }
+    
+    if ( number.Length() > 0)
+        {
+        aNumber.Copy( number );
+        }
+    delete numberBuf;
+    
+	TInt format;
+	
+    if ( !aNumber.Match( KTwoZerosPattern ) && aNumber.Length() > 2 && aNumber[2] != KZero )
+        {
+        format = ETwoZeros;
+        }
+    else if ( !aNumber.Match( KOneZeroPattern )&& aNumber.Length() > 1 && aNumber[1] != KZero )
+        {
+        format = EOneZero;
+        }
+    else if ( !aNumber.Match( KPlusPattern ) && aNumber.Length() > 1 && aNumber[1] != KZero )
+        {
+        format = EPlus;
+        }
+    else if ( aNumber.Length() > 0 && aNumber[0] != KZero && ( ( TChar ) aNumber[0] ).IsDigit() )
+        {
+        format = EDigit;
+        }
+	else
+		{
+        format = EUnknown;
+	    }
+
+    return format;
+    }
+
+TBool CVPbkPhoneNumberMatchStrategyImpl::ValidateBestMatchingRulesL( const TDesC& aNumber )
+    {
+    if ( iPhoneNumberType == ENotInitialized )
+        {
+        TPtr16 phoneNumber = iPhoneNumber->Des();
+        iPhoneNumberType = ( TNumberType ) FormatAndCheckNumberType( phoneNumber );
+        }
+    
+    HBufC* number = aNumber.AllocLC();
+    TPtr16 phoneNumber = number->Des();
+    TNumberType numberType = ( TNumberType ) FormatAndCheckNumberType( phoneNumber );
+
+    TBool match = ( !phoneNumber.Compare( *iPhoneNumber ) ||
+                  CheckBestMatchingRules( *iPhoneNumber, iPhoneNumberType, *number, numberType  ) ||
+                  CheckBestMatchingRules( *number, numberType, *iPhoneNumber, iPhoneNumberType  ) );
+
+    CleanupStack::PopAndDestroy( number );
+
+    return match;
+    }
+
+TBool CVPbkPhoneNumberMatchStrategyImpl::CheckBestMatchingRules(
+        const TDesC& aNumberA, TNumberType aNumberAType,
+        const TDesC& aNumberB, TNumberType aNumberBType  )
+    {
+    TBool result = EFalse;
+    
+    // Rules for matching not identical numbers
+    // Rules details are presented in Best_Number_Matching_Algorithm_Description.doc
+    
+    // rule International-International 1
+    if ( !result && aNumberAType == EPlus && aNumberBType == ETwoZeros )
+        {
+        TPtrC numberA = aNumberA.Right( aNumberA.Length() - 1 );
+        TPtrC numberB = aNumberB.Right( aNumberB.Length() - 2 );
+        result = !( numberA.Compare( numberB ) );
+        if ( result )
+            {
+            return result;
+            }
+        }
+
+    // rule International-International 2
+    if ( aNumberAType == EPlus && aNumberBType == EDigit )
+        {
+        TPtrC numberA = aNumberA.Right( aNumberA.Length() - 1 );
+        if ( numberA.Length() < aNumberB.Length() )
+            {
+            TPtrC numberB = aNumberB.Right( numberA.Length() );
+            result = !( numberA.Compare( numberB ) );
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+
+    // rule International-International 3
+    if ( aNumberAType == ETwoZeros && aNumberBType == EDigit )
+        {
+        TPtrC numberA = aNumberA.Right( aNumberA.Length() - 2 );
+        if ( numberA.Length() < aNumberB.Length() )
+            {
+            TPtrC numberB = aNumberB.Right( numberA.Length() );
+            result = !( numberA.Compare( numberB ) );
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+
+    // rule International-Operator 1
+    if ( aNumberAType == EOneZero && aNumberBType == EPlus
+            || aNumberAType == EDigit && aNumberBType == EPlus )
+        {
+        TPtrC numberA;
+        if ( aNumberAType == EOneZero )
+            {
+            numberA.Set( aNumberA.Right( aNumberA.Length() - 1 ) );
+            }
+        else
+            {
+            numberA.Set( aNumberA );
+            }
+        if ( numberA.Length() < aNumberB.Length() - 1 )
+            {
+            TPtrC numberB = aNumberB.Right( numberA.Length() );
+            result = !( numberA.Compare( numberB ) );
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+
+    // rule International-Operator 2
+    if ( aNumberAType == EOneZero && aNumberBType == ETwoZeros
+            || aNumberAType == EDigit && aNumberBType == ETwoZeros )
+        {
+        TPtrC numberA;
+        if ( aNumberAType == EOneZero )
+            {
+            numberA.Set( aNumberA.Right( aNumberA.Length() - 1 ) );
+            }
+        else
+            {
+            numberA.Set( aNumberA );
+            }
+        if ( numberA.Length() < aNumberB.Length() - 2 )
+            {
+            TPtrC numberB = aNumberB.Right( numberA.Length() );
+            result = !( numberA.Compare( numberB ) );
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+
+    // rule International-Operator 3
+    if ( aNumberAType == EOneZero && aNumberBType == EDigit
+            || aNumberAType == EDigit && aNumberBType == EDigit )
+        {
+        TPtrC numberA;
+        if ( aNumberAType == EOneZero )
+            {
+            numberA.Set( aNumberA.Right( aNumberA.Length() - 1 ) );
+            }
+        else
+            {
+            numberA.Set( aNumberA );
+            }
+        if ( numberA.Length() < aNumberB.Length() )
+            {
+            TPtrC numberB = aNumberB.Right( numberA.Length() );
+            result = !( numberA.Compare( numberB ) );
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+
+    // rule Operator-Operator 1
+    if ( aNumberAType == EOneZero && aNumberBType == EDigit )
+        {
+        TPtrC numberA = aNumberA.Right( aNumberA.Length() - 1 );
+        result = !( numberA.Compare( aNumberB ) );
+            {
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+    
+    // rule North America Numbering Plan 1
+    if ( aNumberAType == EDigit && aNumberBType == EPlus )
+        {
+        TPtrC numberB = aNumberB.Right( aNumberB.Length() - 1 );
+        result = !( aNumberA.Compare( numberB ) );
+            {
+            if ( result )
+                {
+                return result;
+                }
+            }
+        }
+
+    // More exceptional acceptance rules can be added here
+	// Keep rules updated in the document Best_Number_Matching_Algorithm_Description.doc
+
+    return result;
+    }
+
+CVPbkContactStoreUriArray* CVPbkPhoneNumberMatchStrategyImpl::GetCurrentStoreConfigurationL()
+    {
+    CRepository* repository = CRepository::NewL( TUid::Uid( KCRUidPhonebookStoreConfiguration ) );
+    CleanupStack::PushL( repository );
+    CVPbkContactStoreUriArray* result = CVPbkContactStoreUriArray::NewLC();
+
+    RArray<TUint32> configurationKeys;
+    CleanupClosePushL( configurationKeys );
+
+    repository->FindL( KPhonebookCurrentConfigurationPartialKey,
+            KPhonebookCurrentConfigurationMask, configurationKeys );
+
+    HBufC* buffer = HBufC::NewLC( KInitialStoreUriSize );
+    const TInt keyCount = configurationKeys.Count();
+    TInt ret = KErrNone;
+    for ( TInt i = 0; i < keyCount; ++i )
+        {
+        TPtr ptr = buffer->Des();
+        ptr.Zero();
+        TInt actualSize = 0;
+        ret = repository->Get( configurationKeys[i], ptr, actualSize );
+        if ( ret == KErrOverflow )
+            {
+            CleanupStack::PopAndDestroy(); // buffer
+            buffer = HBufC::NewLC( actualSize );
+            ptr.Set( buffer->Des() );
+            ret = repository->Get( configurationKeys[i], ptr );
+            }
+        
+        if ( ret != KErrNone )
+            {
+            break;
+            }
+        
+        if( !result->IsIncluded( TVPbkContactStoreUriPtr( ptr ) ) )  // Only append if the uri is not yet included
+            {
+            result->AppendL( ptr );
+            }
+        }
+    CleanupStack::PopAndDestroy( buffer );
+    CleanupStack::PopAndDestroy( &configurationKeys );
+    CleanupStack::Pop( result );
+    CleanupStack::PopAndDestroy( repository );
+    
+    if ( ret != KErrNone )
+        {
+        delete result;
+        result = NULL;
+        }
+    return result;
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::RefineDuplicatedNumbersL()
+    {
+    CVPbkContactStoreUriArray* stores = GetCurrentStoreConfigurationL();
+    if ( !stores )
+        {
+        return;
+        }
+    CleanupStack::PushL( stores );
+    
+    TInt storesCount = stores->Count();
+    if ( storesCount )
+        {
+        TInt linksCount = iResults->Count();
+        // check if there is in the results at least one contact
+        // from currently used stores
+        TBool isFromUsedStore = EFalse;
+        for ( TInt i = 0; i < linksCount; i++ )
+            {
+            const MVPbkContactStoreProperties& linkStoreProp = 
+                iResults->At( i ).ContactStore().StoreProperties();
+
+            for ( TInt j = 0; j < storesCount; j++ )
+                {
+                if ( !linkStoreProp.Uri().UriDes().Compare( ( *stores )[j].UriDes() ) )
+                    {
+                    isFromUsedStore = ETrue;
+                    break;
+                    }
+                }
+            if ( isFromUsedStore )
+                {
+                break;
+                }
+            }
+        // remove from results contacts from not used stores
+        if ( isFromUsedStore )
+            {
+            for ( TInt i = 0; i < linksCount; i++ )
+                {
+                TBool remove = ETrue;
+                const MVPbkContactStoreProperties& linkStoreProp = 
+                    iResults->At( i ).ContactStore().StoreProperties();
+                
+                for ( TInt j = 0; j < storesCount; j++ )
+                    {
+                    if ( !linkStoreProp.Uri().UriDes().Compare( ( *stores )[j].UriDes() ) )
+                        {
+                        remove = EFalse;
+                        break;
+                        }
+                    }
+                if ( remove )
+                    {
+                    iResults->Delete( i );
+                    linksCount--;
+                    i--;
+                    }
+                }
+            }
+        }
+    CleanupStack::PopAndDestroy( stores );
+    }
+
+TBool CVPbkPhoneNumberMatchStrategyImpl::IsSimStore( const MVPbkContactStore& aStore )
+    {
+    TVPbkContactStoreUriPtr uriPtr = aStore.StoreProperties().Uri();
+    if ( !uriPtr.UriDes().Compare( KVPbkSimGlobalAdnURI )
+            || !uriPtr.UriDes().Compare( KVPbkSimGlobalFdnURI )
+            || !uriPtr.UriDes().Compare( KVPbkSimGlobalSdnURI )
+            || !uriPtr.UriDes().Compare( KVPbkSimGlobalOwnNumberURI ) )
+        {
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+void CVPbkPhoneNumberMatchStrategyImpl::LoadNumberParserPluginL()
+    {    
+    RImplInfoPtrArray   implInfoArray;
+    CleanupResetAndDestroyPushL( implInfoArray );
+    REComSession::ListImplementationsL( KUidEcomCntPhoneNumberParserInterface, 
+                                        implInfoArray );
+    // Load the first implementation found for KUidEcomCntPhoneNumberParserInterface 
+    const TInt count = implInfoArray.Count();
+    __ASSERT_ALWAYS( count > 0, User::Leave( KErrNotFound ) );
+    const TUid firstImplementationFound = implInfoArray[0]->ImplementationUid();
+    iParser = reinterpret_cast<CContactPhoneNumberParser*> 
+        ( CContactEcomPhoneNumberParser::NewL( firstImplementationFound ) );
+    CleanupStack::PopAndDestroy( &implInfoArray );
+    }
+
+CVPbkPhoneNumberMatchStrategy::CVPbkPhoneNumberMatchStrategy()
+    {
+    }
+
+EXPORT_C CVPbkPhoneNumberMatchStrategy* CVPbkPhoneNumberMatchStrategy::NewL(
+        const TConfig& aConfig,
+        CVPbkContactManager& aContactManager,
+        MVPbkContactFindObserver& aObserver)
+    {
+    if (aConfig.iMatchMode == EVPbkSequentialMatch)
+        {
+        return CVPbkPhoneNumberSequentialMatchStrategy::NewL(aConfig, aContactManager, aObserver);
+        }
+    else
+        {
+        return CVPbkPhoneNumberParallelMatchStrategy::NewL(aConfig, aContactManager, aObserver);
+        }
+   }
+
+CVPbkPhoneNumberMatchStrategy::~CVPbkPhoneNumberMatchStrategy()
+    {
+    delete iImpl;
+    }
+
+EXPORT_C void CVPbkPhoneNumberMatchStrategy::MatchL(const TDesC& aPhoneNumber)
+    {
+    InitMatchingL();
+
+    iImpl->MatchL(aPhoneNumber);
+    }
+
+void CVPbkPhoneNumberMatchStrategy::BaseConstructL(
+        const TConfig& aConfig,
+        CVPbkContactManager& aContactManager,
+        MVPbkContactFindObserver& aObserver)
+    {
+    iImpl = CVPbkPhoneNumberMatchStrategyImpl::NewL(
+            *this, aConfig, aContactManager, aObserver);
+    }
+
+MVPbkContactFindObserver& CVPbkPhoneNumberMatchStrategy::FindObserver() const
+    {
+    return *iImpl;
+    }
+
+TInt CVPbkPhoneNumberMatchStrategy::MaxMatchDigits() const
+    {
+    return iImpl->MaxMatchDigits();
+    }
+
+TArray<MVPbkContactStore*> CVPbkPhoneNumberMatchStrategy::StoresToMatch() const
+    {
+    return iImpl->StoresToMatch();
+    }
+
+TBool CVPbkPhoneNumberMatchStrategy::IsSimStore( const MVPbkContactStore& aStore )
+    {
+    return iImpl->IsSimStore( aStore );
+    }
+// End of File