homescreensrv_plat/context_utility_api/tsrc/src/hgctxcontactmatcher.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:54:17 +0200
changeset 0 79c6a41cd166
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2008 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:  Contact matching class
*
*/


// System includes
#include <e32base.h>
#include <bamdesca.h>
#include <cntitem.h>
#include <eikenv.h>
#include <bautils.h>
#include <fbs.h>
#include <imageconversion.h>
#include <data_caging_path_literals.hrh>

#include <CVPbkContactManager.h>
#include <MVPbkContactStoreList.h>
#include <MVPbkContactStore.h>
#include <CVPbkContactStoreUriArray.h>
#include <MVPbkContactLinkArray.h>
#include <MVPbkContactLink.h>
#include <MVPbkFieldType.h>
#include <MVPbkStoreContact.h>
#include <MVPbkStoreContactField.h>
#include <MVPbkStoreContactFieldCollection.h>
#include <MVPbkContactFieldData.h>
#include <MVPbkContactFieldTextData.h>
#include <MVPbkContactFieldUriData.h>
#include <MVPbkContactFieldDateTimeData.h>
#include <MVPbkContactFieldBinaryData.h>
#include <MVPbkContactOperationBase.h>
#include <MVPbkContactStoreProperties.h>
#include <TVPbkContactStoreUriPtr.h>
#include <VPbkContactStoreUris.h>
#include <MPbk2ContactNameFormatter.h>
#include <CVPbkFieldTypeSelector.h>
#include <TVPbkFieldVersitProperty.h>
#include <CVPbkFieldTypeRefsList.h>
#include <TVPbkWordParserCallbackParam.h>
#include <CVPbkContactViewDefinition.h>
#include <MVPbkContactViewBase.h>
#include <coemain.h>
#include <CPbk2SortOrderManager.h>
#include <Pbk2ContactNameFormatterFactory.h>

#include "hgctxcontactmatcher.h"


#include "hgctxutilslogging.h"


// ================= Static Constant Data ===================

typedef const TDesC& (*UriFuncPtr)();

// Number match store URIs in priority order.
// When doing number matching, order of the stores in the uri array will
// determine which stores are searched first (sequential match). We stop
// the search when first match is found.
static const UriFuncPtr NumberMatchStoreUris[] =
    {
    VPbkContactStoreUris::DefaultCntDbUri,
    // If we don't manage to open some store, we remove it from our array
    VPbkContactStoreUris::SimGlobalAdnUri,
    VPbkContactStoreUris::SimGlobalSdnUri,
    NULL,   // end marker
    };

// All store URIs except own number store
static const UriFuncPtr AllStoreUris[] =
    {
    VPbkContactStoreUris::DefaultCntDbUri,
    // If we don't manage to open some store, we remove it from our array
    VPbkContactStoreUris::SimGlobalAdnUri,
    VPbkContactStoreUris::SimGlobalSdnUri,
    VPbkContactStoreUris::SimGlobalFdnUri,
    NULL,   // end marker
    };

// Own number store URIs
static const UriFuncPtr OwnNumberStoreUris[] =
    {
    VPbkContactStoreUris::SimGlobalOwnNumberUri,
    NULL,   // end marker
    };

// number of digits that must match from the right side of a phone number
const TInt KNumberMatchLenFromRight = 7;

// granularity for CDesCArray
const TInt KArrayGranularity = 4;

//               YYYYMMDD:HHMMSS.MMMMMM
_LIT(KNullTime, "11110000:010101.00000");

// ================= STATIC FUNCTIONS =======================

// ---------------------------------------------------------
// FindWordSplitterL
// ---------------------------------------------------------
//
static TInt FindWordSplitterL( TAny* aParams )
	{
	TVPbkWordParserCallbackParam* parser = 
        static_cast<TVPbkWordParserCallbackParam*>( aParams );
        
    const TText* ptr = parser->iStringToParse->Ptr();
	const TText* end = ptr + parser->iStringToParse->Length();

	const TText* startOfWord=NULL;
	for ( ; ; )
		{
		if ( ptr==end || TChar(*ptr).IsSpace() || *ptr == ',' || *ptr == ';' )
			{
			if ( startOfWord )
				{
				TPtrC addWord( startOfWord,ptr - startOfWord );
				parser->iWordArray->AppendL( addWord );
				startOfWord = NULL;
				}
			if ( ptr == end )
                {
				break;
                }
			}
		else if ( !startOfWord )
            {
			startOfWord = ptr;
            }
		ptr++;
		}
	return( KErrNone );
	}

static HBufC* CombineStringsLC( CDesCArray& aArray )
    {
    TInt len = 0;
    for ( TInt i = 0, ie = aArray.Count(); i != ie; ++i )
        {
        len += aArray[i].Length() + 1;
        }
    HBufC* result = HBufC::NewLC( len );
    TPtr p( result->Des() );
    for ( TInt i = 0, ie = aArray.Count(); i != ie; ++i )
        {
        if ( i )
            {
            p.Append( ' ' );
            }
        p.Append( aArray[i] );
        }
    return result;
    }
    
// ================= MEMBER FUNCTIONS =======================

// ----------------------------------------------------------------------------
// Two-phase constructor for CHgCtxContactMatcher class.
// ----------------------------------------------------------------------------
EXPORT_C CHgCtxContactMatcher* CHgCtxContactMatcher::NewL(
    RFs* aFsSession )
    {
    CHgCtxContactMatcher* self = CHgCtxContactMatcher::NewLC( aFsSession );
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// Two-phase constructor for CHgCtxContactMatcher class.
// ----------------------------------------------------------------------------
EXPORT_C CHgCtxContactMatcher* CHgCtxContactMatcher::NewLC(
    RFs* aFsSession )
    {
    CHgCtxContactMatcher* self = new ( ELeave ) CHgCtxContactMatcher( aFsSession );
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// ----------------------------------------------------------------------------
// C++ destructor.
// ----------------------------------------------------------------------------
EXPORT_C CHgCtxContactMatcher::~CHgCtxContactMatcher()
    {
    delete iNameFieldTypes;
    delete iNumberFieldTypes;
    delete iEmailFieldTypes;
    delete iXspIdFieldTypes;
    delete iAddressFieldTypes;
	delete iWebAddressFieldTypes;
    delete iHomeAddressFieldTypes;
    delete iWorkAddressFieldTypes;
    
    FreeOldOperation();
    CleanupNumberMatch();
    delete iStoreUris;
    delete iContactManager;
    delete iSortOrderManager;
    delete iNameFormatter;

    if ( iClientStatus )
        {
        User::RequestComplete( iClientStatus, KErrCancel );
        }
    if ( iASchedulerWait.IsStarted() )
        {
        iASchedulerWait.AsyncStop();
        }
        
    iContactObservers.Close();
    
    if ( iFsSessionOwned && iFsSession )
        {
        iFsSession->Close();
        delete iFsSession;
        }
    }

// ----------------------------------------------------------------------------
// C++ Constructor.
// ----------------------------------------------------------------------------
CHgCtxContactMatcher::CHgCtxContactMatcher( RFs* aFsSession) : iFsSession( aFsSession )
    {
    }

// ----------------------------------------------------------------------------
// Second phase constructor
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::ConstructL()
    {
    if ( !iFsSession )
        {
        // The contact manager would be okay with NULL but some of our own functions
        // need an RFs.
        iFsSessionOwned = ETrue;
        iFsSession = new ( ELeave ) RFs;
        User::LeaveIfError( iFsSession->Connect() );
        }
        
    iContactManager = CVPbkContactManager::NewL(
        *CVPbkContactStoreUriArray::NewLC(), iFsSession );
    CleanupStack::PopAndDestroy(); // CVPbkContactStoreUriArray

    // No stores open yet
    iStoreUris = CVPbkContactStoreUriArray::NewL();
    }

//******************* API-methods *********************************************

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenStoreL(
    const CVPbkContactStoreUriArray& aUriArray )
    {
    InitOperationL( EOpenStore );
    OpenStoreCommonL( aUriArray );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        // Wait until stores are open
        iASchedulerWait.Start();
        }
    User::LeaveIfError( iError );
    }

// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenStoreL(
    const CVPbkContactStoreUriArray& aUriArray, TRequestStatus&  aStatus )
    {
    InitOperationL( EOpenStore );
    OpenStoreCommonL( aUriArray );
    InitOperation( &aStatus );

    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        }
    }


// ----------------------------------------------------------------------------
// Common code to sync/async versions.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::OpenStoreCommonL(
    const CVPbkContactStoreUriArray& aUriArray )
    {
    if (iStoreUris->Count())
        {
        // Opening more stores when some stores are already open is not
        // supported. Support would require managing iStoreUris properly
        // so that it contains all open stores.
        User::Leave(KErrGeneral);
        }

    const TInt count = aUriArray.Count();
    
    for (TInt i = 0; i < count; ++i)
        {
        // Appended Uri:s to the array. If store fails to open it is removed
        // from the array. This keeps Uri's in priority order in the array.
        TVPbkContactStoreUriPtr uriPtr = aUriArray[i];
        iStoreUris->AppendL( uriPtr );

        iContactManager->LoadContactStoreL( uriPtr );
        }
    MVPbkContactStoreList& storeList = iContactManager->ContactStoresL();
    storeList.OpenAllL( *this );
    }

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenAllStoresL()
    {
    OpenStoreL(AllStoreUris);
    }

// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenAllStoresL( TRequestStatus& aStatus )
    {
    OpenStoreL(AllStoreUris, aStatus);
    }

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenDefaultMatchStoresL()
    {
    OpenStoreL(NumberMatchStoreUris);
    }

// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenDefaultMatchStoresL( TRequestStatus& aStatus )
    {
    OpenStoreL(NumberMatchStoreUris, aStatus);
    }

// ----------------------------------------------------------------------------
// Open OwnNumber stores.
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenOwnNumberStoresL()
    {
    OpenStoreL(OwnNumberStoreUris);
    }

// ----------------------------------------------------------------------------
// Open OwnNumber stores.
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::OpenOwnNumberStoresL( TRequestStatus& aStatus )
    {
    OpenStoreL(OwnNumberStoreUris, aStatus);
    }

// ----------------------------------------------------------------------------
// Close all open stores.
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::CloseStoresL()
    {
    // Closing stores does not work. MatchDataL() finds contacts from
    // closed stores.

    InitOperationL( ECloseStores );

    iApiMethodStatus = EExecuting;
    TRAPD( err, iContactManager->ContactStoresL().CloseAll( *this ) );
    iApiMethodStatus = EFinished;
    if ( err == KErrNone)
        {
        delete iStoreUris; iStoreUris = NULL;
        iStoreUris = CVPbkContactStoreUriArray::NewL();        
        }
    else
        {
        User::Leave(err);
        }
    }

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::MatchPhoneNumberL(
    const TDesC& aData, TInt aDigits,
    CVPbkPhoneNumberMatchStrategy::TVPbkPhoneNumberMatchFlags aFlags,
    CVPbkContactLinkArray& aLinkArray )
    {
    InitOperationL( EMatchPhoneNumber );
    iResultContactLinkArray = &aLinkArray;

    // Start asynchronous matching and wait until results are ready
    MatchPhoneNumberCommonL( aData, aDigits, aFlags );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        iASchedulerWait.Start();
        }
    User::LeaveIfError( iError );
    }


// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::MatchPhoneNumberL(
    const TDesC& aData, TInt aDigits,
    CVPbkPhoneNumberMatchStrategy::TVPbkPhoneNumberMatchFlags aFlags,
    CVPbkContactLinkArray& aLinkArray, TRequestStatus& aStatus )
    {
    InitOperationL( EMatchPhoneNumber );
    iResultContactLinkArray = &aLinkArray;
    // Start asynchronous matching
    MatchPhoneNumberCommonL( aData, aDigits, aFlags );
    InitOperation( &aStatus );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        }
    }

// ----------------------------------------------------------------------------
// Common code for sync and async versions
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::MatchPhoneNumberCommonL(
    const TDesC& aData, TInt aDigits,
    CVPbkPhoneNumberMatchStrategy::TVPbkPhoneNumberMatchFlags aFlags )
    {
    // Delete resources allocated for previous match
    CleanupNumberMatch();

    // iStoreUris is filled when stores are opened

    iStratConfig = new (ELeave) CVPbkPhoneNumberMatchStrategy::TConfig(
        aDigits,
        *iStoreUris,
        CVPbkPhoneNumberMatchStrategy::EVPbkSequentialMatch,
        aFlags);
    iMatchStrategy = CVPbkPhoneNumberMatchStrategy::NewL(
                *iStratConfig,
                *iContactManager,
                *this);
    // Start asynchronous matching
    iMatchStrategy->MatchL( aData );
    }


// ----------------------------------------------------------------------------
// Find from a store succeeded
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::FindFromStoreSucceededL( MVPbkContactStore& /*aStore*/,
        MVPbkContactLinkArray* aResultsFromStore )
    {
    __ASSERT_DEBUG( aResultsFromStore, HgContactMatcherPanics::Panic(
        HgContactMatcherPanics::EPanNullPointer ));

    // Take the ownership of the result immediately
    CleanupDeletePushL( aResultsFromStore );

    CopyFindResultsL( aResultsFromStore );

    CleanupStack::PopAndDestroy(); // aResultsFromStore
    }

// ----------------------------------------------------------------------------
// Copy the found results for a store into array
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::CopyFindResultsL( MVPbkContactLinkArray*
    aResults )
    {
    const TInt count = aResults->Count();
    if ( iResultContactLinkArray )
        {
        // Copy links to the member array
        for ( TInt i = 0; i < count; ++i )
            {
            iResultContactLinkArray->AppendL( aResults->At( i ).CloneLC() );
            CleanupStack::Pop(); // cloned link
            }
        }
    else
        {
        iResultContactLinkCnt += count;
        }
    }


// ----------------------------------------------------------------------------
// Find failed
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::FindFromStoreFailed( MVPbkContactStore& /*aStore*/, TInt /*aError*/ )
    {
    //no operation, search to continue from the other stores
    }


// ----------------------------------------------------------------------------
// Find complete
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::FindFromStoresOperationComplete()
    {
    if (!iResultContactLinkArray)
        {
        // Links were not copied. Result is whether any links found or not.
        OperationComplete( iResultContactLinkCnt ? KErrNone:KErrNotFound );
        }
    else
        {
        OperationComplete();
        iResultContactLinkArray = NULL;
        }
    }

// ----------------------------------------------------------------------------
// Return global list of field types.
// ----------------------------------------------------------------------------
EXPORT_C const MVPbkFieldTypeList& CHgCtxContactMatcher::FieldTypes() const
    {
    return iContactManager->FieldTypes();
    }

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetStoreContactL(
    const MVPbkContactLink& aLink, MVPbkStoreContact** aStoreContact )
    {
    InitOperationL( EGetStoreContact );
    iResultStoreContact = aStoreContact;

    // Start asynchronous operation and wait until results are ready
    FreeOldOperation();
    iOperation = iContactManager->RetrieveContactL( aLink, *this );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        iASchedulerWait.Start();
        }
    User::LeaveIfError( iError );
    }

// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetStoreContactL(
    const MVPbkContactLink& aLink, MVPbkStoreContact** aStoreContact,
    TRequestStatus& aStatus )
    {
    InitOperationL( EGetStoreContact );
    iResultStoreContact = aStoreContact;
    // Start asynchronous operation
    FreeOldOperation();
    iOperation = iContactManager->RetrieveContactL( aLink, *this );
    InitOperation( &aStatus );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        }
    }

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::IsOwnNumberL( const TDesC& aNumber, TBool& aResult )
    {
    InitOperationL( EMatchPhoneNumber );

     // Not interested in links, only whether found or not
    iResultContactLinkArray = NULL;
    iResultContactLinkCnt = 0;

    // Start asynchronous matching and wait until results are ready
    MatchPhoneNumberCommonL( aNumber, aNumber.Length(),
        CVPbkPhoneNumberMatchStrategy::EVPbkStopOnFirstMatchFlag );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        iASchedulerWait.Start();
        }
    User::LeaveIfError( iError );

    aResult = iResultContactLinkCnt > 0;
    }

// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::IsOwnNumberL( const TDesC& aNumber,
    TRequestStatus& aStatus )
    {
    InitOperationL( EMatchPhoneNumber );

     // Not interested in links, only whether found or not
    iResultContactLinkArray = NULL;
    iResultContactLinkCnt = 0;

    // Start asynchronous matching
    MatchPhoneNumberCommonL( aNumber, aNumber.Length(),
        CVPbkPhoneNumberMatchStrategy::EVPbkStopOnFirstMatchFlag );
    InitOperation( &aStatus );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        }
    }

// ----------------------------------------------------------------------------
// Cancel asynchronous operation
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::CancelOperation()
    {
    if (iApiMethodStatus != EExecuting)
        {
        return;
        }

    __ASSERT_DEBUG(!iSync, HgContactMatcherPanics::Panic(
        HgContactMatcherPanics::EPanInvalidOp));

    switch(iApiMethod)
        {
        case EMatchData:
        case EGetStoreContact:
            FreeOldOperation(); // deleting the operation cancels it
            break;
        case EMatchPhoneNumber:
            CleanupNumberMatch();
            break;
        default:
            ;
        }

    User::RequestComplete( iClientStatus, KErrCancel );

    iApiMethod = ENoMethod;
    iApiMethodStatus = EFinished;
    }

// ----------------------------------------------------------------------------
// GetFieldData, for EVPbkFieldStorageTypeText
// ----------------------------------------------------------------------------
EXPORT_C TPtrC CHgCtxContactMatcher::GetFieldDataTextL(
    const MVPbkStoreContact& aContact,
    const MVPbkFieldType& aFType ) const
    {
    TPtrC ret(KNullDesC);
    const MVPbkStoreContactField* field = FindField( aContact, aFType);
    if (field)
        {
        const MVPbkContactFieldData& fdata = field->FieldData();
        if (fdata.DataType() == EVPbkFieldStorageTypeText)
            {
            const MVPbkContactFieldTextData& fdata2 =
                MVPbkContactFieldTextData::Cast(fdata);
            ret.Set( fdata2.Text() );
            }
        else
            {
            User::Leave( KErrArgument );
            }
        }
    return ret;
    }

// ----------------------------------------------------------------------------
// GetFieldData, for EVPbkFieldStorageTypeDateTime
// ----------------------------------------------------------------------------
EXPORT_C TTime CHgCtxContactMatcher::GetFieldDataDateTimeL(
    const MVPbkStoreContact& aContact,
    const MVPbkFieldType& aFType ) const
    {
    TTime ret(KNullTime);
    const MVPbkStoreContactField* field = FindField( aContact, aFType);
    if (field)
        {
        const MVPbkContactFieldData& fdata = field->FieldData();
        if (fdata.DataType() == EVPbkFieldStorageTypeDateTime)
            {
            const MVPbkContactFieldDateTimeData& fdata2 =
                MVPbkContactFieldDateTimeData::Cast( fdata );
            ret = fdata2.DateTime();
            }
        else
            {
            User::Leave( KErrArgument );
            }
        }
    return ret;
    }

// ----------------------------------------------------------------------------
// GetFieldData, for EVPbkFieldStorageTypeBinary
// ----------------------------------------------------------------------------
EXPORT_C TPtrC8 CHgCtxContactMatcher::GetFieldDataBinaryL(
    const MVPbkStoreContact& aContact,
    const MVPbkFieldType& aFType ) const
    {
    TPtrC8 ret(KNullDesC8);
    const MVPbkStoreContactField* field = FindField( aContact, aFType);
    if (field)
        {
        const MVPbkContactFieldData& fdata = field->FieldData();
        if (fdata.DataType() == EVPbkFieldStorageTypeBinary)
            {
            const MVPbkContactFieldBinaryData& fdata2 =
                MVPbkContactFieldBinaryData::Cast( fdata );
            ret.Set( fdata2.BinaryData() );
            }
        else
            {
            User::Leave( KErrArgument );
            }
        }
    return ret;
    }


//******************************** Private Methods ***************************

// ----------------------------------------------------------------------------
// Finds a field of given type from contact.
// Returns pointer to field or NULL if not found.
// ----------------------------------------------------------------------------
 const MVPbkStoreContactField* CHgCtxContactMatcher::FindField(
    const MVPbkStoreContact& aContact,
    const MVPbkFieldType& aFType ) const
    {
    const MVPbkStoreContactFieldCollection& coll = aContact.Fields();
    TInt n = coll.FieldCount();

    const MVPbkStoreContactField* field = NULL;
    TBool bFound = EFalse;
    for(TInt i=0; i < n && !bFound; ++i)
        {
        field = &coll.FieldAt( i );
        const MVPbkFieldType* ftype = field->MatchFieldType( 0 );
        if ( ftype )
            {
            if ( ftype->IsSame( aFType ))
                {
                bFound = ETrue;
                }
            }
        }
    if ( !bFound )
        {
        field = NULL;
        }
    return field;
    }

// ----------------------------------------------------------------------------
// Get URI array with stores
// ----------------------------------------------------------------------------
CVPbkContactStoreUriArray* CHgCtxContactMatcher::GetStoreArrayLC(
    const TDesC& (* const aFuncPtrs[])() )
    {
    CVPbkContactStoreUriArray* uriArray = CVPbkContactStoreUriArray::NewLC();

    // Add stores
    for(TInt i = 0; aFuncPtrs[i]; i++)
        {
        TVPbkContactStoreUriPtr uriPtr(aFuncPtrs[i]());
        uriArray->AppendL(uriPtr);
        }
    return uriArray;
    }

// ----------------------------------------------------------------------------
// Open stores. Synchronous version
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::OpenStoreL(const TDesC& (* const aFuncPtrs[])())
    {
    CVPbkContactStoreUriArray* uriArray = GetStoreArrayLC(aFuncPtrs);

    CHgCtxContactMatcher::OpenStoreL(*uriArray);
    CleanupStack::PopAndDestroy(uriArray);
    }

// ----------------------------------------------------------------------------
// Open stores. Asynchronous version
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::OpenStoreL(const TDesC& (* const aFuncPtrs[])(),
    TRequestStatus&  aStatus)
    {
    CVPbkContactStoreUriArray* uriArray = GetStoreArrayLC(aFuncPtrs);

    CHgCtxContactMatcher::OpenStoreL(*uriArray, aStatus);
    CleanupStack::PopAndDestroy(uriArray);
    }

// ----------------------------------------------------------------------------
// Called when the opening process is complete,
// ie. all stores have been reported either failed or successfully opened.
// ----------------------------------------------------------------------------
//
void CHgCtxContactMatcher::OpenComplete()
    {
    TInt error = KErrNone;
    if ( iStoreUris->Count() == 0 )
        {
        // unable to open any of the specified stores
        error = KErrNotSupported;
        }
    OperationComplete( error );
    }

// ----------------------------------------------------------------------------
// Called when a contact store is ready to use.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::StoreReady( MVPbkContactStore& /*aContactStore*/ )
    {
    }

// ----------------------------------------------------------------------------
// Called when a contact store becomes unavailable.
// Client may inspect the reason of the unavailability and decide whether or not
// it will keep the store opened (ie. listen to the store events).
// @param aContactStore The store that became unavailable.
// @param aReason The reason why the store is unavailable.
//                This is one of the system wide error codes.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::StoreUnavailable( MVPbkContactStore& aContactStore,
    TInt /*aReason*/ )
    {
    // Remove contact store from uri list
    iStoreUris->Remove( aContactStore.StoreProperties().Uri() );
    }

// ----------------------------------------------------------------------------
// Called when changes occur in the contact store.
// @see TVPbkContactStoreEvent
//
// @param aStoreEvent Event that has occured.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::HandleStoreEventL(
        MVPbkContactStore& /*aContactStore*/,
        TVPbkContactStoreEvent aStoreEvent)
    {
    // Contact and group events can be ignored, but we pass backup events for the observer.
    switch ( aStoreEvent.iEventType )
        {
        case TVPbkContactStoreEvent::EStoreBackupBeginning:
        case TVPbkContactStoreEvent::EStoreRestoreBeginning:
            {
            iBackup = ETrue;
            break;
            }
        case TVPbkContactStoreEvent::EStoreBackupRestoreCompleted:
            {
            iBackup = EFalse;
            break;
            }
        case TVPbkContactStoreEvent::EContactAdded:
        case TVPbkContactStoreEvent::EContactDeleted:
        case TVPbkContactStoreEvent::EContactChanged:
            {
            for ( TInt i = 0, ie = iContactObservers.Count(); i != ie; ++i )
                {
                iContactObservers[i]->HandleContactEventL();
                }
            break;
            }
        default:
            break;
        }
    }


// ----------------------------------------------------------------------------
// Called when find is complete. Callee takes ownership of the results.
// In case of an error during find, the aResults may contain only
// partial results of the find.
//
// @param aResults Array of contact links that matched the find.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::FindCompleteL( MVPbkContactLinkArray* aResults )
    {
    __ASSERT_DEBUG( aResults, HgContactMatcherPanics::Panic(
        HgContactMatcherPanics::EPanNullPointer ));

    // Take the ownership of the result immediately
    CleanupDeletePushL( aResults );

    CopyFindResultsL( aResults );

    CleanupStack::PopAndDestroy(); // aResults

    if (!iResultContactLinkArray)
        {
        // No need to copy links. Only interested whether found or not
        OperationComplete( iResultContactLinkCnt ? KErrNone:KErrNotFound );
        }
    else
        {
        OperationComplete();
        iResultContactLinkArray = NULL;
        }
    }

// ----------------------------------------------------------------------------
// Called in case the find fails for some reason.
//
// @param aError One of the system wide error codes.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::FindFailed( TInt aError )
    {
    OperationFailed( aError );
    iResultContactLinkArray = NULL;
    }

// ----------------------------------------------------------------------------
// Free old VPbk-operation.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::FreeOldOperation()
    {
    delete iOperation;
    iOperation = NULL;
    }

// ----------------------------------------------------------------------------
// Called when operation is completed.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::VPbkSingleContactOperationComplete(
        MVPbkContactOperationBase& /*aOperation*/, MVPbkStoreContact* aContact)
    {
    *iResultStoreContact = aContact;
    iResultStoreContact  = NULL;
    OperationComplete();
    }

// ----------------------------------------------------------------------------
// Called if the operation fails.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::VPbkSingleContactOperationFailed(
    MVPbkContactOperationBase& /*aOperation*/, TInt aError)
    {
    OperationFailed( aError );
    }

// ----------------------------------------------------------------------------
// Set member variables for sync operation
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::InitOperationL( TMethodId aMethod )
    {
    if ( iBackup )
        {
        User::Leave( KErrAccessDenied );
        }

    // Check whether operation is in progress
    if ( iApiMethodStatus == EExecuting )
        {
        User::Leave( KErrInUse );
        }

    iSync  = ETrue;
    iError = KErrNone;
    iApiMethod = aMethod;
    iApiMethodStatus = EIdle;
    }

// ----------------------------------------------------------------------------
// Set member variables for async operation
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::InitOperationL( TMethodId aMethod, TRequestStatus* aStatus )
    {
    InitOperationL( aMethod );

    iSync  = EFalse;
    iClientStatus  = aStatus;
    *iClientStatus = KRequestPending;
    }
    
// ----------------------------------------------------------------------------
// Set member variables for async operation
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::InitOperation( TRequestStatus* aStatus )
    {
    iSync  = EFalse;
    iClientStatus  = aStatus;
    *iClientStatus = KRequestPending;
    }

// ----------------------------------------------------------------------------
// Sync/async operation finished succesfully, return results to method caller.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::OperationComplete( TInt aErrorCode )
    {
    if (iSync)
        {
        if ( iASchedulerWait.IsStarted() )
            {
            iASchedulerWait.AsyncStop();
            }
        }
    else
        {
        if ( iClientStatus )
            {
            User::RequestComplete( iClientStatus, aErrorCode );
            iClientStatus = NULL;
            }
        }
    iApiMethodStatus = EFinished;
    }

// ----------------------------------------------------------------------------
// Sync/async operation failed, return results to method caller.
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::OperationFailed( TInt aError )
    {
    iError = aError;
    OperationComplete( aError );
    }

// ----------------------------------------------------------------------------
// Free resources allocated for number matching
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::CleanupNumberMatch()
{
    delete iMatchStrategy;
    iMatchStrategy = NULL;

    delete iStratConfig;
    iStratConfig = NULL;

    // store uris are not deleted here - opened array remains valid
    // until new set of stores is opened.
}

// ---------------------------------------------------------------------------
// CHgCtxContactMatcher::GetContactStoresL
// ---------------------------------------------------------------------------
EXPORT_C MVPbkContactStoreList& CHgCtxContactMatcher::GetContactStoresL()
    {
    return iContactManager->ContactStoresL();
    }


// -----------------------------------------------------------------------------
// TInt CHgCtxContactMatcher::GetName
//
// Returns the formatted name fo the contact
// -----------------------------------------------------------------------------
EXPORT_C HBufC* CHgCtxContactMatcher::GetNameL( MVPbkStoreContactFieldCollection&
                                                                aFieldCollection )
    {
    MPbk2ContactNameFormatter& nameFormatter = ContactNameFormatterL();
    
    HBufC* formattedName = nameFormatter.GetContactTitleOrNullL( aFieldCollection, 
    						                                     MPbk2ContactNameFormatter::EUseSeparator );
    return formattedName;
    }

// -----------------------------------------------------------------------------
// CVPbkContactManager& CHgCtxContactMatcher::GetContactManager( )
// -----------------------------------------------------------------------------
EXPORT_C CVPbkContactManager& CHgCtxContactMatcher::GetContactManager()
    {
    return *iContactManager;
    }
    

// ----------------------------------------------------------------------------
// Synchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::MatchDataL( const TDesC& aData,
    const MVPbkFieldTypeList& aFieldTypes,
    CVPbkContactLinkArray& aLinkArray)
    {
    InitOperationL( EMatchData );
    iResultContactLinkArray = &aLinkArray;

    // Start asynchronous matching and wait until results are ready
    FreeOldOperation();
    iOperation = iContactManager->FindL(aData, aFieldTypes, *this);
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        iASchedulerWait.Start();
        }

    User::LeaveIfError( iError );
    RemoveSimilarEmailAddressesL( aData, aLinkArray, aFieldTypes );
   	}

// ----------------------------------------------------------------------------
// Remove contacts that do not have exactly the correct email address
// e.g. if cbd@test.com address is requested, the for example a contact with address abcd@test.com will be removed
// from the result.
// This filtering is done only in the syncronous version of MatchDataL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::RemoveSimilarEmailAddressesL( const TDesC& aData, CVPbkContactLinkArray& aLinkArray, const MVPbkFieldTypeList& aFieldTypes )
    {
    TVPbkFieldVersitProperty prop;
    prop.SetName( EVPbkVersitNameEMAIL );
    // do extra checks for email addresses
    
    const MVPbkFieldType* foundType = NULL;
    // Continue only if at least one type is EVPbkVersitNameEMAIL
    TInt i;
    for ( i = 0 ; i < aFieldTypes.FieldTypeCount() ; i++ )
        {
        foundType = &(aFieldTypes.FieldTypeAt( i ));
        if ( foundType->VersitProperties().Count() > 0
            && foundType->VersitProperties()[0].Name() == prop.Name() )
            {
            break;
            }
        }
    if ( i == aFieldTypes.FieldTypeCount() )
    	{
    	// no email types
    	return;
    	}
    
    const MVPbkFieldTypeList& fieldTypeList = FieldTypes();

    TInt index = 0;
	TBool isExactMatch;
    while( index < aLinkArray.Count() )
    	{
	    MVPbkStoreContact* storeContact;
	    GetStoreContactL( aLinkArray.At( index ), &storeContact );
	    storeContact->PushL();
	    
	    isExactMatch = EFalse;
        for ( TInt i = 0; i < fieldTypeList.FieldTypeCount(); i++ )
            {
            // find the email property
            foundType = &(fieldTypeList.FieldTypeAt( i ));
            if ( foundType->VersitProperties().Count() > 0
                && foundType->VersitProperties()[0].Name() == prop.Name() )
                {
                TPtrC src = GetFieldDataTextL(*storeContact, *foundType );
                if ( aData.CompareF( src ) == 0 )
        	    	{
        	    	isExactMatch = ETrue;
        	    	}
                }
            }
	    if ( isExactMatch )
            {
            // go for the next contact
            index++;
            }
        else
        	{
            // remove the contact, because the email address does not match the one queried. 
            // the next one will take plce of this contact in the list (=do not increase index)
            aLinkArray.Delete( index ); 
        	}
	    CleanupStack::PopAndDestroy( storeContact );
    	}
    }

// ----------------------------------------------------------------------------
// Asynchronous version
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::MatchDataL( const TDesC& aData,
    const MVPbkFieldTypeList& aFieldTypes,
    CVPbkContactLinkArray& aLinkArray,
    TRequestStatus& aStatus)
    {
    InitOperationL( EMatchData );
    iResultContactLinkArray = &aLinkArray;

    // Start asynchronous matching
    FreeOldOperation();
    iOperation = iContactManager->FindL(aData, aFieldTypes, *this);
    InitOperation( &aStatus );
    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        }
    }
// ----------------------------------------------------------------------------
// MatchData for searchstrings
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::MatchDataL( const MDesC16Array& aSearchStrings,
    const MVPbkFieldTypeList& aFieldTypes,
    CVPbkContactLinkArray& aLinkArray,
    const TCallBack& aWordParserCallBack )
    {
    InitOperationL( EMatchData );
    iResultContactLinkArray = &aLinkArray;

    // Start asynchronous matching and wait here until results are ready
    FreeOldOperation();
    iOperation = iContactManager->FindL( aSearchStrings, aFieldTypes,
        *this, aWordParserCallBack );

    if ( iApiMethodStatus != EFinished )
        {
        iApiMethodStatus = EExecuting;
        iASchedulerWait.Start();
        }
    User::LeaveIfError( iError );
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::ContactNameFormatterL
// ----------------------------------------------------------------------------
EXPORT_C MPbk2ContactNameFormatter& CHgCtxContactMatcher::ContactNameFormatterL()
    {
    //first initialise, if not already initialised
    if ( !iSortOrderManager )
        {
        iSortOrderManager = CPbk2SortOrderManager::NewL( FieldTypes() );
        }
        
    if ( !iNameFormatter )
        {
        iNameFormatter = Pbk2ContactNameFormatterFactory::CreateL( FieldTypes(),
                                                                  *iSortOrderManager );
        }
    return *iNameFormatter;
    }


// ---------------------------------------------------------------------------
// HgContactMatcherPanics::Panic
//
// Panic function
// ---------------------------------------------------------------------------
void HgContactMatcherPanics::Panic( TPanic aPanic )
    {
    _LIT(KPanicCategory, "ContactMatcher");
    User::Panic( KPanicCategory, aPanic );
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::SplitAndMatchL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::SplitAndMatchL( const TDesC& aData,
        const MVPbkFieldTypeList& aFieldTypes,
        CVPbkContactLinkArray& aLinkArray)
    {
    CDesCArray* wordArray = SplitFindStringL( aData );
    CleanupStack::PushL( wordArray );
    TCallBack findParser( FindWordSplitterL );
    MatchDataL( *wordArray, aFieldTypes, aLinkArray, findParser );
    CleanupStack::PopAndDestroy( wordArray );
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::RegisterContactObserverL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::RegisterContactObserverL(
        MHgCtxContactObserver& aObserver )
    {
    if ( iContactObservers.Find( &aObserver ) == KErrNotFound )
        {
        iContactObservers.AppendL( &aObserver );
        }
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::UnregisterContactObserver
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::UnregisterContactObserver(
        MHgCtxContactObserver& aObserver )
    {
    TInt pos = iContactObservers.Find( &aObserver );
    if ( pos >= 0 )
        {
        iContactObservers.Remove( pos );
        }
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::LookupL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::LookupL( const TDesC& aData,
        CVPbkContactLinkArray& aLinkArray )
    {
    HGLOG_CONTEXT( LookupL, HGLOG_LOCAL );
    HGLOG1_IN( "'%S'", &aData );

    // Take part_A from "part_A <part_B>"
    // or part_A from "part_A".
    TPtrC input( aData );
    TInt ltPos = input.Locate( '<' );
    TInt gtPos = input.Locate( '>' );
    if ( ltPos != KErrNotFound && gtPos> ltPos )
        {
        input.Set( aData.Mid( 0, ltPos ) );
        }
    HBufC* trimmedInput = input.AllocLC();
    trimmedInput->Des().Trim();

    TInt oldCount = aLinkArray.Count();
    if ( IsPhoneNumberL( *trimmedInput ) )
        {
        TryNumberLookupL( *trimmedInput, aLinkArray );
        }
    else
        {
        TryTextLookupL( *trimmedInput, aLinkArray );
        }

    CleanupStack::PopAndDestroy( trimmedInput );

    if ( aLinkArray.Count() == oldCount && ltPos != KErrNotFound && gtPos > ltPos )
        {
        // lookup for part_A was not successful so try part_B
        trimmedInput = aData.Mid( ltPos + 1, gtPos - ltPos - 1 ).AllocLC();
        trimmedInput->Des().Trim();
        if ( IsPhoneNumberL( *trimmedInput ) )
            {
            TryNumberLookupL( *trimmedInput, aLinkArray );
            }
        else
            {
            TryTextLookupL( *trimmedInput, aLinkArray );
            }
        CleanupStack::PopAndDestroy( trimmedInput );
        }
        
    HGLOG1_OUT( "got %d results", aLinkArray.Count() - oldCount );
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateNameFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateNameFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateNameFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iNameFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.SetName( EVPbkVersitNameFN );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNameFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try FN" );
        }

    prop.SetName( EVPbkVersitNameN );
    prop.SetSubField( EVPbkVersitSubFieldGivenName );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNameFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try given name" );
        }
    
    prop.SetName( EVPbkVersitNameN );
    prop.SetSubField( EVPbkVersitSubFieldFamilyName );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNameFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try family name" );
        }
    
    prop.SetName( EVPbkVersitNameORG );
    prop.SetSubField( EVPbkVersitSubFieldOrgName );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNameFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try org name" );
        }
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateEmailFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateEmailFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateEmailFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iEmailFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.SetName( EVPbkVersitNameEMAIL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamINTERNET );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iEmailFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general email" );
        }

    prop.SetName( EVPbkVersitNameEMAIL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamINTERNET );
    prop.Parameters().Add( EVPbkVersitParamWORK );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iEmailFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work email" );
        }

    prop.SetName( EVPbkVersitNameEMAIL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamINTERNET );
    prop.Parameters().Add( EVPbkVersitParamHOME );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iEmailFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home email" );
        }
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateXspIdFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateXspIdFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateXspIdFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iXspIdFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.SetName( EVPbkVersitNameIMPP );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iXspIdFieldTypes->AppendL( *t );
        }
        
    HGLOG1_OUT( "found %d xsp id field types",
        iXspIdFieldTypes->FieldTypeCount() );
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateNumberFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateNumberFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateNumberFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iNumberFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.SetName( EVPbkVersitNameTEL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamCELL );
    prop.Parameters().Add( EVPbkVersitParamHOME );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNumberFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home mobile" );
        }

    prop.SetName( EVPbkVersitNameTEL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamCELL );
    prop.Parameters().Add( EVPbkVersitParamWORK );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNumberFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work mobile" );
        }

    prop.SetName( EVPbkVersitNameTEL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamCELL );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNumberFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general mobile" );
        }

    prop.SetName( EVPbkVersitNameTEL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamHOME );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNumberFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home landline" );
        }

    prop.SetName( EVPbkVersitNameTEL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    prop.Parameters().Add( EVPbkVersitParamWORK );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNumberFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work landline" );
        }

    prop.SetName( EVPbkVersitNameTEL );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    prop.Parameters().Reset();
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iNumberFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general landline" );
        }
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateAddressFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateAddressFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateAddressFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldCountry );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general country" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldRegion );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general region" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldLocality );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general locality" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldStreet );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try general street" );
        }
        
    HGLOG_OUT();
    }


// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateWebAddressFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iWebAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.Parameters().Add( EVPbkVersitParamPREF );
    prop.SetName( EVPbkVersitNameURL );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWebAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try prefered url" );
        }        
    
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateWebAddressHomeFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateWebAddressHomeFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iWebAddressHomeFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.Parameters().Add( EVPbkVersitParamHOME );
    prop.SetName( EVPbkVersitNameURL );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWebAddressHomeFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home url" );
        }   
    
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateWebAddressWorkFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateWebAddressWorkFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iWebAddressWorkFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.Parameters().Add( EVPbkVersitParamWORK );
    prop.SetName( EVPbkVersitNameURL );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWebAddressWorkFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work url" );
        }      
    
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateHomeAddressFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateHomeAddressFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateHomeAddressFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iHomeAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;
    prop.Parameters().Add( EVPbkVersitParamHOME );

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldCountry );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iHomeAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home country" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldRegion );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iHomeAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home region" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldLocality );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iHomeAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home locality" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldStreet );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iHomeAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try home street" );
        }
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::PreCreateWorkAddressFieldTypesL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::PreCreateWorkAddressFieldTypesL()
    {
    HGLOG_CONTEXT( PreCreateWorkAddressFieldTypesL, HGLOG_LOCAL );
    HGLOG_IN();

    iWorkAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;
    prop.Parameters().Add( EVPbkVersitParamWORK );

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldCountry );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWorkAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work country" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldRegion );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWorkAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work region" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldLocality );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWorkAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work locality" );
        }

    prop.SetName( EVPbkVersitNameADR );
    prop.SetSubField( EVPbkVersitSubFieldStreet );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        iWorkAddressFieldTypes->AppendL( *t );
        HGLOG0( HGLOG_INFO, "will try work street" );
        }
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::TryTextLookupL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::TryTextLookupL( const TDesC& aName,
        CVPbkContactLinkArray& aLinkArray )
    {
    HGLOG_CONTEXT( TryTextLookupL, HGLOG_LOCAL );
    HGLOG_IN();

    CVPbkFieldTypeRefsList* fieldTypes = CVPbkFieldTypeRefsList::NewL();
    CleanupStack::PushL( fieldTypes );

    // try name and email and ovi id fields
    if ( !iNameFieldTypes )
        {
        PreCreateNameFieldTypesL();
        }
    for ( TInt i = 0, ie = iNameFieldTypes->FieldTypeCount(); i != ie; ++i )
        {
        fieldTypes->AppendL( iNameFieldTypes->FieldTypeAt( i ) );
        }
    if ( !iEmailFieldTypes )
        {
        PreCreateEmailFieldTypesL();
        }
    for ( TInt i = 0, ie = iEmailFieldTypes->FieldTypeCount(); i != ie; ++i )
        {
        fieldTypes->AppendL( iEmailFieldTypes->FieldTypeAt( i ) );
        }
    if ( !iXspIdFieldTypes )
        {
        PreCreateXspIdFieldTypesL();
        }
    for ( TInt i = 0, ie = iXspIdFieldTypes->FieldTypeCount(); i != ie; ++i )
        {
        fieldTypes->AppendL( iXspIdFieldTypes->FieldTypeAt( i ) );
        }

    SplitAndMatchL( aName, *fieldTypes, aLinkArray );

    CleanupStack::PopAndDestroy( fieldTypes );
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::TryNumberLookupL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::TryNumberLookupL( const TDesC& aNumber,
        CVPbkContactLinkArray& aLinkArray )
    {
    HGLOG_CONTEXT( TryNumberLookupL, HGLOG_LOCAL );
    HGLOG_IN();
    
    MatchPhoneNumberL( aNumber,
        KNumberMatchLenFromRight,
        CVPbkPhoneNumberMatchStrategy::EVPbkMatchFlagsNone,
        aLinkArray );
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetTextFieldsL
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::GetTextFieldsL(
        const CVPbkFieldTypeRefsList& aList,
        const MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray )
    {
    HGLOG_CONTEXT( GetTextFieldsL, HGLOG_LOCAL );
    HGLOG_IN();
        
    for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
        {
        const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
        const MVPbkFieldType* type = field.BestMatchingFieldType();
        if ( type && aList.ContainsSame( *type ) )
            {
            const MVPbkContactFieldData& fdata( field.FieldData() );
            if ( fdata.DataType() == EVPbkFieldStorageTypeText )
                {
                const MVPbkContactFieldTextData& fdata2 =
                    MVPbkContactFieldTextData::Cast( fdata );
                const TDesC& text( fdata2.Text() );
                aArray.AppendL( text );
                HGLOG1( HGLOG_INFO, "found: '%S'", &text );
                }
            }
        }
        
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetNumbersL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetNumbersL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray )
    {
    HGLOG_CONTEXT( GetNumbersL, HGLOG_LOCAL );
    HGLOG_IN();

    if ( !iNumberFieldTypes )
        {
        PreCreateNumberFieldTypesL();
        }
    GetTextFieldsL( *iNumberFieldTypes, aFieldCollection, aArray );

    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetEmailAddressesL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetEmailAddressesL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray )
    {
    HGLOG_CONTEXT( GetEmailAddressesL, HGLOG_LOCAL );
    HGLOG_IN();

    if ( !iEmailFieldTypes )
        {
        PreCreateEmailFieldTypesL();
        }
    GetTextFieldsL( *iEmailFieldTypes, aFieldCollection, aArray );

    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetAddressesL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetAddressesL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray )
    {
    HGLOG_CONTEXT( GetAddressesL, HGLOG_LOCAL );
    HGLOG_IN();
    
    CDesC16ArrayFlat* arr = new ( ELeave ) CDesC16ArrayFlat( KArrayGranularity );
    CleanupStack::PushL( arr );

    if ( !iAddressFieldTypes )
        {
        PreCreateAddressFieldTypesL();
        }
    GetTextFieldsL( *iAddressFieldTypes, aFieldCollection, *arr );
    if ( arr->Count() )
        {
        HBufC* combined = CombineStringsLC( *arr );
        aArray.AppendL( *combined );
        HGLOG1( HGLOG_INFO, "added '%S'", combined );
        CleanupStack::PopAndDestroy( combined );
        }

    arr->Reset();
    if ( !iHomeAddressFieldTypes )
        {
        PreCreateHomeAddressFieldTypesL();
        }
    GetTextFieldsL( *iHomeAddressFieldTypes, aFieldCollection, *arr );
    if ( arr->Count() )
        {
        HBufC* combined = CombineStringsLC( *arr );
        aArray.AppendL( *combined );
        HGLOG1( HGLOG_INFO, "added '%S'", combined );
        CleanupStack::PopAndDestroy( combined );
        }

    arr->Reset();
    if ( !iWorkAddressFieldTypes )
        {
        PreCreateWorkAddressFieldTypesL();
        }
    GetTextFieldsL( *iWorkAddressFieldTypes, aFieldCollection, *arr );
    if ( arr->Count() )
        {
        HBufC* combined = CombineStringsLC( *arr );
        aArray.AppendL( *combined );
        HGLOG1( HGLOG_INFO, "added '%S'", combined );
        CleanupStack::PopAndDestroy( combined );
        }

    CleanupStack::PopAndDestroy( arr );
    HGLOG_OUT();
    }


// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetWebAddressesL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetWebAddressesL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray,
        TWebAddressesType aType  )
    {
    HGLOG_CONTEXT( GetWebAddressesL, HGLOG_LOCAL );
    HGLOG_IN();
    CVPbkFieldTypeRefsList* addressFieldTypes( NULL );
    
    switch ( aType )
        {
        case EWebAddresses:
            {
            if ( !iWebAddressFieldTypes )
               {
               PreCreateWebAddressFieldTypesL();
               }
            addressFieldTypes = iWebAddressFieldTypes;
            }
            break;
            
        case EWebAddressesHome:
            {
            if ( !iWebAddressHomeFieldTypes )
               {
               PreCreateWebAddressHomeFieldTypesL();
               }
            addressFieldTypes = iWebAddressHomeFieldTypes;
            }
            break;

        case EWebAddressesWork:
            {
            if ( !iWebAddressWorkFieldTypes )
                {
                PreCreateWebAddressWorkFieldTypesL();
                }
            addressFieldTypes = iWebAddressWorkFieldTypes;
            }
            break;
            
        default:
            break;
        }
    
    if( addressFieldTypes )
        {
        GetTextFieldsL( *addressFieldTypes, aFieldCollection, aArray );
        }
    
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetThumbnailL
// ----------------------------------------------------------------------------
EXPORT_C CFbsBitmap* CHgCtxContactMatcher::GetThumbnailL(
        MVPbkStoreContactFieldCollection& aFieldCollection )
    {
    HGLOG_CONTEXT( GetThumbnailL, HGLOG_LOCAL );
    HGLOG_IN();
    
    CFbsBitmap* result = 0;
    TVPbkFieldVersitProperty prop;
    prop.SetName( EVPbkVersitNamePHOTO );
    const MVPbkFieldType* t = FieldTypes().FindMatch( prop, 0 );
    if ( t )
        {
        HGLOG0( HGLOG_INFO, "photo field type found" );
        for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
            {
            const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
            const MVPbkFieldType* type = field.BestMatchingFieldType();
            if ( type && type->IsSame( *t ) )
                {
                const MVPbkContactFieldData& fdata( field.FieldData() );
                if ( fdata.DataType() == EVPbkFieldStorageTypeBinary )
                    {
                    HGLOG0( HGLOG_INFO, "found thumbnail" );
                    const MVPbkContactFieldBinaryData& fdata2 =
                        MVPbkContactFieldBinaryData::Cast( fdata );
                    TPtrC8 data( fdata2.BinaryData() );
                    CImageDecoder* decoder = 0;
                    // DataNewL does not seem to work properly with
                    // EOptionAlwaysThread, it will hang in WaitForRequest
                    // for ever, at least in the panel app.
                    // So write the image to a temporary file (duhhh...)
                    // and use FileNewL.
                    RFile f;
                    TFileName tempFileName;
                    iFsSession->CreatePrivatePath( EDriveC );
                    iFsSession->PrivatePath( tempFileName );
                    _LIT( KDriveC, "C:" );
                    _LIT( KTempName, "hgctxthumb" );
                    tempFileName.Insert( 0, KDriveC );
                    tempFileName.Append( KTempName );
                    HGLOG1( HGLOG_INFO, "tempfn='%S'", &tempFileName );
                    User::LeaveIfError( f.Replace( *iFsSession, tempFileName,
                                    EFileWrite ) );
                    f.Write( data, data.Length() );
                    f.Close();
                    TRAPD( err, decoder = CImageDecoder::FileNewL( *iFsSession,
                                    tempFileName,
                                    CImageDecoder::EOptionAlwaysThread ) );
                    HGLOG1( HGLOG_INFO, "decoder NewL result: %d", err );
                    if ( err == KErrNone )
                        {
                        CleanupStack::PushL( decoder );
                        result = new ( ELeave ) CFbsBitmap;
                        CleanupStack::PushL( result );
                        TSize sz( decoder->FrameInfo().iOverallSizeInPixels );
                        TDisplayMode mode( decoder->FrameInfo().iFrameDisplayMode );
                        HGLOG3( HGLOG_INFO, "size=%dx%d, mode=%d", sz.iWidth,
                                sz.iHeight, mode );
                        User::LeaveIfError( result->Create( sz, mode ) );
        
                        TRequestStatus status;
                        HGLOG0( HGLOG_INFO, "starting to convert" );
                        decoder->Convert( &status, *result );
                        User::WaitForRequest( status );
                        HGLOG1( HGLOG_INFO, "decoder Convert result: %d",
                                status.Int() );
                        CleanupStack::Pop( result );
                        CleanupStack::PopAndDestroy( decoder );
        
                        if ( status.Int() != KErrNone )
                            {
                            delete result;
                            result = 0;
                            }
                        else
                            {
                            // stop and return the bitmap
                            break;
                            }
                        }                    
                    }
                }
            }
        }
        
    HGLOG_OUT();
    return result;
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::IsPhoneNumberL
// ----------------------------------------------------------------------------
EXPORT_C TBool CHgCtxContactMatcher::IsPhoneNumberL( const TDesC& aData )
    {
    TBool result = EFalse;
    CFindItemEngine::SFoundItem item;
    CFindItemEngine* search = CFindItemEngine::NewL( aData,
        CFindItemEngine::EFindItemSearchPhoneNumberBin );
    if ( search->ItemCount() )
        {
        search->Item( item );
        result = item.iStartPos == 0;
        }
    delete search;
    return result;
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::IsEmailAddressL
// ----------------------------------------------------------------------------
EXPORT_C TBool CHgCtxContactMatcher::IsEmailAddressL( const TDesC& aData )
    {
    TBool result = EFalse;
    CFindItemEngine::SFoundItem item;
    CFindItemEngine* search = CFindItemEngine::NewL( aData,
        CFindItemEngine::EFindItemSearchMailAddressBin );
    if ( search->ItemCount() )
        {
        search->Item( item );
        result = item.iStartPos == 0;
        }
    delete search;
    return result;
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetNamesForFindL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetNamesForFindL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray )
    {
    CVPbkFieldTypeRefsList* nameTypes = CVPbkFieldTypeRefsList::NewL();
    CleanupStack::PushL( nameTypes );
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;
    
    prop.SetName( EVPbkVersitNameN );
    prop.SetSubField( EVPbkVersitSubFieldGivenName );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        nameTypes->AppendL( *t );
        }
    
    prop.SetName( EVPbkVersitNameN );
    prop.SetSubField( EVPbkVersitSubFieldFamilyName );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        nameTypes->AppendL( *t );
        }
    
    for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
        {
        const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
        t = field.MatchFieldType( 0 );
        if ( t && nameTypes->ContainsSame( *t ) )
            {
            const MVPbkContactFieldData& fdata( field.FieldData() );
            if ( fdata.DataType() == EVPbkFieldStorageTypeText )
                {
                const MVPbkContactFieldTextData& fdata2 =
                    MVPbkContactFieldTextData::Cast( fdata );
                aArray.AppendL( fdata2.Text() );
                }
            }
        }

    CleanupStack::PopAndDestroy( nameTypes );
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetNamesForFindL
// ----------------------------------------------------------------------------
EXPORT_C HBufC* CHgCtxContactMatcher::GetNamesForFindL(
        MVPbkStoreContactFieldCollection& aFieldCollection )
    {
    CDesC16ArrayFlat* arr = new ( ELeave ) CDesC16ArrayFlat( KArrayGranularity );
    CleanupStack::PushL( arr );
    GetNamesForFindL( aFieldCollection, *arr );
    HBufC* result = CombineStringsLC( *arr );
    CleanupStack::Pop( result );
    CleanupStack::PopAndDestroy( arr );
    return result;
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::SplitFindStringL
// ----------------------------------------------------------------------------
EXPORT_C CDesCArray* CHgCtxContactMatcher::SplitFindStringL(const TDesC& aFindString)
    {
	CDesCArray* wordArray = new ( ELeave ) CDesCArrayFlat( KArrayGranularity );
	CleanupStack::PushL( wordArray );	
	
    TVPbkWordParserCallbackParam parser( &aFindString, wordArray );
	FindWordSplitterL( &parser );
	
	CleanupStack::Pop(); // wordArray
	return parser.iWordArray;
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::SplitMsgContactL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::SplitMsgContactL( const TDesC& aString,
        CDesCArray& aArray )
    {
    TInt pos = aString.Locate( '<' );
    if ( pos >= 0 )
        {
        // skip spaces before '<'
        TInt endPos = pos - 1;
        while ( endPos > 0 && TChar( aString[endPos] ).IsSpace() )
            {
            --endPos;
            }
        // take the text before '<'
        aArray.AppendL( aString.Left( endPos + 1 ) );
        // take the text between '<' and '>'
        TInt closePos = aString.Locate( '>' );
        if ( closePos > pos )
            {
            aArray.AppendL( aString.Mid( pos + 1, closePos - pos - 1 ) );
            }
        }
    else
        {
        aArray.AppendL( aString );
        }
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetCustomFieldL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetCustomFieldL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray& aArray,
        TVPbkFieldTypeName aVersitName,
        TVPbkFieldTypeParameter aVersitParam )
    {
    HGLOG_CONTEXT( GetCustomFieldL, HGLOG_LOCAL );
    HGLOG_IN();
    
    CVPbkFieldTypeRefsList* typeList = GetCustomFieldTypeLC(
        aVersitName, aVersitParam );

    GetTextFieldsL( *typeList, aFieldCollection, aArray );
    
    CleanupStack::PopAndDestroy( typeList );
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetCustomFieldTypeLC
// ----------------------------------------------------------------------------
EXPORT_C CVPbkFieldTypeRefsList* CHgCtxContactMatcher::GetCustomFieldTypeLC(
        TVPbkFieldTypeName aVersitName,
        TVPbkFieldTypeParameter aVersitParam )
    {
    HGLOG_CONTEXT( GetCustomFieldTypeLC, HGLOG_LOCAL );
    HGLOG_IN();
    
    CVPbkFieldTypeRefsList* typeList = CVPbkFieldTypeRefsList::NewL();
    CleanupStack::PushL( typeList );
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;

    prop.SetName( aVersitName );
    prop.Parameters().Add( aVersitParam );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        typeList->AppendL( *t );
        HGLOG0( HGLOG_INFO, "field found" );
        }

    HGLOG_OUT();
    return typeList;
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::GetImppFieldL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::GetImppFieldL(
        MVPbkStoreContactFieldCollection& aFieldCollection,
        CDesCArray* aSchemeOnlyArray,
        CDesCArray* aUriOnlyArray,
        CDesCArray* aFullArray )
    {
    HGLOG_CONTEXT( GetImppFieldL, HGLOG_LOCAL );
    HGLOG_IN();

    // this function will not build on TUBE
    CVPbkFieldTypeRefsList* typeList = CVPbkFieldTypeRefsList::NewL();
    CleanupStack::PushL( typeList );
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* t;
    prop.SetName( EVPbkVersitNameIMPP );
    t = types.FindMatch( prop, 0 );
    if ( t )
        {
        typeList->AppendL( *t );
        HGLOG0( HGLOG_INFO, "type found" );
        }
    for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
        {
        const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
        const MVPbkFieldType* type = field.BestMatchingFieldType();
        if ( type && typeList->ContainsSame( *type ) )
            {
            const MVPbkContactFieldData& fdata( field.FieldData() );
            HGLOG1( HGLOG_INFO, "field found %d", fdata.DataType() );
            if ( fdata.DataType() == EVPbkFieldStorageTypeUri )
                {
                const MVPbkContactFieldUriData& fdata2 =
                    MVPbkContactFieldUriData::Cast( fdata );
                const TDesC& schemeOnly( fdata2.Scheme() );
                const TDesC& uriOnly( fdata2.Text() );
                const TDesC& fullText( fdata2.Uri() );
                HGLOG3( HGLOG_INFO, "'%S' + '%S' = '%S'",
                    &schemeOnly, &uriOnly, &fullText );
                if ( aSchemeOnlyArray )
                    {
                    aSchemeOnlyArray->AppendL( schemeOnly );
                    }
                if ( aUriOnlyArray )
                    {
                    aUriOnlyArray->AppendL( uriOnly );
                    }
                if ( aFullArray )
                    {
                    aFullArray->AppendL( fullText );
                    }
                }
            }
        }                    
    CleanupStack::PopAndDestroy( typeList );
    
    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::FindContactWithBirthdayL
// ----------------------------------------------------------------------------
EXPORT_C void CHgCtxContactMatcher::FindContactWithBirthdayL(
        const TTime& aDate,
        CVPbkContactLinkArray& aLinkArray )
    {
    HGLOG_CONTEXT( FindContactWithBirthdayL, HGLOG_LOCAL );
    HGLOG1_IN( "%Ld", aDate.Int64() );

    // extract month and day
    TDateTime dt = aDate.DateTime();
    TInt month = dt.Month();
    TInt day = dt.Day();
    HGLOG2( HGLOG_INFO, "wanted month = %d day = %d", month, day );

    CVPbkFieldTypeRefsList* emptyList = CVPbkFieldTypeRefsList::NewL();
    CleanupStack::PushL( emptyList );

    // create view with all contacts
    CVPbkContactViewDefinition* def = CVPbkContactViewDefinition::NewLC();
    def->SetType( EVPbkContactsView );
    def->SetUriL( VPbkContactStoreUris::DefaultCntDbUri() );
    MVPbkContactViewBase* view = iContactManager->CreateContactViewLC(
        *this, *def, *emptyList );

    HGLOG0( HGLOG_INFO, "starting wait" );
    iASchedulerWait.Start();
    HGLOG0( HGLOG_INFO, "after wait" );

    // view is ready
    TInt ctCount = view->ContactCountL();
    HGLOG1( HGLOG_INFO, "contact count: %d", ctCount );

    // find the birthday field type
    const MVPbkFieldTypeList& types( FieldTypes() );
    TVPbkFieldVersitProperty prop;
    const MVPbkFieldType* bdayFt;
    prop.SetName( EVPbkVersitNameBDAY );
    prop.SetSubField( EVPbkVersitSubFieldNone );
    bdayFt = types.FindMatch( prop, 0 );

    if ( bdayFt && ctCount )
        {
        HGLOG0( HGLOG_INFO, "found bday field type" );
        TTime nullTime( KNullTime );
        // go through all contacts and check birthday field values
        for ( TInt i = 0; i < ctCount; ++i )
            {
            MVPbkContactLink* link( view->CreateLinkLC( i ) );
            MVPbkStoreContact* contact = 0;
            GetStoreContactL( *link, &contact );
            if ( contact )
                {
                HGLOG1( HGLOG_INFO, "got contact, idx %d", i );
                contact->PushL();
                TTime bday;
                bday = GetFieldDataDateTimeL( *contact, *bdayFt );
                if ( bday != nullTime )
                    {
                    HGLOG1( HGLOG_INFO, "found bday %Ld", bday.Int64() );
                    dt = bday.DateTime();
                    TInt thisMonth = dt.Month();
                    TInt thisDay = dt.Day();
                    HGLOG2( HGLOG_INFO, "for this contact month = %d day = %d",
                        thisMonth, thisDay );
                    if ( thisMonth == month && thisDay == day )
                        {
                        HGLOG0( HGLOG_INFO, "match" );
                        aLinkArray.AppendL( link );
                        link = 0;
                        }
                    }
                CleanupStack::PopAndDestroy(); // contact
                }
            CleanupStack::Pop(); // if matched then no ownership and link is NULL by now
            delete link;
            }
        }

    CleanupStack::PopAndDestroy(); // view
    CleanupStack::PopAndDestroy( def );
    CleanupStack::PopAndDestroy( emptyList );

    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::ContactViewReady
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::ContactViewReady(
        MVPbkContactViewBase& aView ) 
    {
    HGLOG_CONTEXT( ContactViewReady, HGLOG_LOCAL );
    HGLOG_IN();

    if ( iASchedulerWait.IsStarted() )
        {
        iASchedulerWait.AsyncStop();
        }

    aView.RemoveObserver( *this ); 

    HGLOG_OUT();
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::ContactViewUnavailable
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::ContactViewUnavailable(
        MVPbkContactViewBase& /*aView*/ )
    {
    // means that view is unavailable for now
    // but ContactViewReady will be called at some point
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::ContactAddedToView
// ----------------------------------------------------------------------------
void CHgCtxContactMatcher::ContactAddedToView(
        MVPbkContactViewBase& /*aView*/, 
        TInt /*aIndex*/,
        const MVPbkContactLink& /*aContactLink*/ )
    {
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::ContactRemovedFromView
// ----------------------------------------------------------------------------
 void CHgCtxContactMatcher::ContactRemovedFromView(
        MVPbkContactViewBase& /*aView*/, 
        TInt /*aIndex*/, 
        const MVPbkContactLink& /*aContactLink*/ )
    {
    }

// ----------------------------------------------------------------------------
// CHgCtxContactMatcher::ContactViewError
// ----------------------------------------------------------------------------
 void CHgCtxContactMatcher::ContactViewError(
        MVPbkContactViewBase& aView, 
        TInt aError, 
        TBool /*aErrorNotified*/ )
    {
    HGLOG_CONTEXT( ContactViewError, HGLOG_LOCAL );
    HGLOG1_IN( "aError = %d", aError );

    if ( iASchedulerWait.IsStarted() )
        {
        iASchedulerWait.AsyncStop();
        }

    aView.RemoveObserver( *this ); 
    
    HGLOG_OUT();
    }


// End of File