// Copyright (c) 2006-2009 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:
//
#include <cntdb.h>
#include "pbapserver.h"
#include "pbappbhandlecache.h"
#include "btaccesshostlog.h"
/*static*/ CPbapPbHandleCache* CPbapPbHandleCache::NewL(CContactDatabase& aDatabase, MPbHandleCacheObserver& aObserver)
{
LOG_STATIC_FUNC
CPbapPbHandleCache* self=new(ELeave) CPbapPbHandleCache(aDatabase, aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CPbapPbHandleCache::CPbapPbHandleCache(CContactDatabase& aDatabase, MPbHandleCacheObserver& aObserver)
: iDatabase(aDatabase), iObserver(aObserver)
{
LOG_FUNC
}
CPbapPbHandleCache::~CPbapPbHandleCache()
{
LOG_FUNC
iHandleList.Close();
delete iChangeNotifier;
}
void CPbapPbHandleCache::ConstructL()
{
LOG_FUNC
iChangeNotifier = CContactChangeNotifier::NewL(iDatabase, this);
CreateHandleListL();
}
TInt CPbapPbHandleCache::HandleAtL(TUint aIndex) const
{
LOG_FUNC
if(aIndex >= Count())
{
__ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicIndexOutOfBoundry));
User::Leave(KErrOverflow);
}
return iHandleList[aIndex].iHandle;
}
TContactItemId CPbapPbHandleCache::ContactIdAtL(TUint aIndex) const
{
LOG_FUNC
if(aIndex >= Count())
{
__ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicIndexOutOfBoundry));
User::Leave(KErrOverflow);
}
return iHandleList[aIndex].iContactId;
}
TInt CPbapPbHandleCache::FindHandle(TInt aHandle) const
{
LOG_FUNC
// the array is ordered on handle so can use fast binary search
TPbHandleAndId item(aHandle, KNullContactId);
return iHandleList.FindInOrder(item, TLinearOrder<TPbHandleAndId>(CompareHandles));
}
TInt CPbapPbHandleCache::FindContactId(TContactItemId aContactId) const
{
LOG_FUNC
// slow sequential search of array required for contact ids
TPbHandleAndId item(KErrNotFound, aContactId);
return iHandleList.Find(item, TIdentityRelation<TPbHandleAndId>(MatchContactIds));
}
/*static*/
TInt CPbapPbHandleCache::CompareHandles(const TPbHandleAndId& aFirst, const TPbHandleAndId& aSecond)
{
LOG_STATIC_FUNC
return (aFirst.iHandle - aSecond.iHandle);
}
/*static*/
TBool CPbapPbHandleCache::MatchContactIds(const TPbHandleAndId& aFirst, const TPbHandleAndId& aSecond)
{
LOG_STATIC_FUNC
return (aFirst.iContactId == aSecond.iContactId);
}
void CPbapPbHandleCache::CreateHandleListL()
{
LOG_FUNC
iHandleList.Reset();
// add own card handle item
TContactItemId ownCardId = iDatabase.OwnCardId();
TPbHandleAndId ownCardItem(KOwnCardHandle, ownCardId);
iHandleList.AppendL(ownCardItem);
// only include contact cards and the own card when building list
iDatabase.SetDbViewContactType(KUidContactCard);
// iterate through database building sorted list of handles
// (there should be a faster way of getting all the ids in the database,
// calling CContactDatabase::SortedItemsL() without a sort order used to
// be the quickest method but that has been deprecated)
TContactIter iter(iDatabase);
TContactItemId contactId = iter.FirstL();
TInt handle = 1;
while (contactId != KNullContactId)
{
if (contactId != ownCardId)
{
TPbHandleAndId item(handle, contactId);
iHandleList.AppendL(item);
++handle; // increment handle
}
contactId = iter.NextL();
}
}
void CPbapPbHandleCache::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
{
LOG_FUNC
switch(aEvent.iType)
{
case EContactDbObserverEventContactChanged:
{
// notify observer that a contact in the cache has changed
iObserver.HandleCacheChanged();
}
break;
case EContactDbObserverEventContactAdded:
{
// add contact id to cache (ignoring insert errors) and notify observer
HandleContactAddedL(aEvent.iContactId);
iObserver.HandleCacheChanged();
}
break;
case EContactDbObserverEventContactDeleted:
{
// remove contact id from cache and notify observer
HandleContactDeleted(aEvent.iContactId);
iObserver.HandleCacheChanged();
}
break;
case EContactDbObserverEventOwnCardChanged:
{
// the own card has been modified or another contact
// has been assigned as the own card
HandleOwnCardChangedL();
iObserver.HandleCacheChanged();
}
break;
case EContactDbObserverEventOwnCardDeleted:
{
// reset own card id back to KNullContactId
HandleOwnCardDeleted();
iObserver.HandleCacheChanged();
}
break;
case EContactDbObserverEventUnknownChanges:
{
// the database has changed but we do not know which
// contacts were affected, only choice is to rebuild handles cache
#ifdef _DEBUG
TRAPD(error, CreateHandleListL());
if(error != KErrNone)
{
__ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicUnexpectedError));
User::Leave(error);
}
#else
TRAP_IGNORE(CreateHandleListL());
#endif // _DEBUG
iObserver.HandleCacheChanged();
}
break;
default:
break;
}
}
void CPbapPbHandleCache::HandleContactAddedL(TContactItemId aContactId)
{
LOG_FUNC
TPbHandleAndId item(NextAvailableHandleL(), aContactId);
iHandleList.AppendL(item);
}
void CPbapPbHandleCache::HandleContactDeleted(TContactItemId aContactId)
{
LOG_FUNC
TInt index= FindContactId(aContactId);
if (index != KErrNotFound)
{
iHandleList.Remove(index);
}
}
void CPbapPbHandleCache::HandleOwnCardChangedL()
{
LOG_FUNC
TContactItemId ownCardId=iDatabase.OwnCardId();
TInt ownCardItemIndex = FindHandle(KOwnCardHandle); // always present
if(ownCardItemIndex == KErrNotFound)
{
__ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicOwnCardNotFound));
User::Leave(KErrNotFound);
}
TContactItemId currentOwnCardId = ContactIdAtL(ownCardItemIndex);
if (ownCardId != currentOwnCardId)
{
if (currentOwnCardId != KNullContactId)
{
// current own card now just another contact so assign to a new handle
TPbHandleAndId item(NextAvailableHandleL(), currentOwnCardId);
iHandleList.Append(item); // ignore the append error
}
// the new own card may already exist in the handle list, if so
// remove it
if (ownCardId != KNullContactId)
{
TInt index = FindContactId(ownCardId);
if (index != KErrNotFound)
{
iHandleList.Remove(index);
}
}
// replace contact id associated with own card handle
ownCardItemIndex = FindHandle(KOwnCardHandle);
iHandleList[ownCardItemIndex].iContactId = ownCardId;
}
}
void CPbapPbHandleCache::HandleOwnCardDeleted()
{
LOG_FUNC
// reset own card id to null id
TInt ownCardItemIndex = FindHandle(KOwnCardHandle);
iHandleList[ownCardItemIndex].iContactId = KNullContactId;
}
TInt CPbapPbHandleCache::NextAvailableHandleL() const
{
LOG_FUNC
TInt lastHandle = HandleAtL(iHandleList.Count()-1);
return (lastHandle + 1); // just increment handle
}