predictivesearch/PcsAlgorithm/Algorithm1/src/CPcsCache.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 14 Sep 2010 20:54:53 +0300
branchRCL_3
changeset 21 9da50d567e3c
parent 20 f4a778e096c2
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Holds the contact information in memory. It maintains a 
*                master array of all contacts. It also has 10 pools corresponding
*                to each key id in the keyboard. Based on numeric key char of 
*                first char of firstname/ lastname a contact is added to one of the
*                pools. Implements MDataStoreObserver interface functions to
*                add/ remove contacts.
*
*/


// INCLUDE FILES
#include <MVPbkContactLink.h>
#include <vpbkeng.rsg>
#include "CPcsDefs.h"
#include "CPsData.h"
#include "CPcsCache.h"
#include "CPcsDebug.h"
#include "CWords.h"
#include "CPcsAlgorithm1Utils.h"
#include "CPcsAdaptiveGridItem.h"

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

// ----------------------------------------------------------------------------
// CPcsCache::NewL
// Two Phase Construction
// ----------------------------------------------------------------------------
CPcsCache* CPcsCache::NewL(const TDesC& aURI, CPcsKeyMap& aKeyMap, TUint8 aUriId)
{
    PRINT ( _L("Enter CPcsCache::NewL") );
    
	CPcsCache* instance= new ( ELeave ) CPcsCache();

	CleanupStack::PushL( instance );

	instance->ConstructL(aURI, aKeyMap, aUriId);

	CleanupStack::Pop( instance );

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

	return instance;    
} 

// ----------------------------------------------------------------------------
// CPcsCache::CPcsCache
// Constructor
// ----------------------------------------------------------------------------
CPcsCache::CPcsCache()
{
    PRINT ( _L("Enter CPcsCache::CPcsCache") );
    PRINT ( _L("End CPcsCache::CPcsCache") );
}

// ----------------------------------------------------------------------------
// CPcsCache::ConstructL
// 2nd Phase Constructor
// ----------------------------------------------------------------------------
void CPcsCache::ConstructL(const TDesC& aURI, CPcsKeyMap& aKeyMap, TUint8 aUriId)
{
    PRINT ( _L("Enter CPcsCache::ConstructL") );

    PRINT2 ( _L("CPcsCache::ConstructL: aURI=%S, aUriId=%d"), &aURI, aUriId);
    
    iURI = aURI.AllocL();
    iUriId = aUriId;
    //Update the caching status for this cache
    iCacheStatus = ECachingNotStarted;
    
    iKeyMap = &aKeyMap;        

    // Populate iKeyArr
    for(TInt i= 0; i <aKeyMap.PoolCount();i++ )
        {
        RPointerArray<CPcsPoolElement> *keyMap = new (ELeave) RPointerArray<CPcsPoolElement>(1);
        iKeyArr.InsertL(keyMap,i);
        }

    // Adaptive Grid map
    if ( iURI->Compare( KVPbkDefaultCntDbURI ) == 0
            || iURI->Compare( KVPbkSimGlobalAdnURI ) == 0
            || iURI->Compare( KVPbkSimGlobalFdnURI ) == 0 
            || iURI->Compare( KVPbkSimGlobalSdnURI ) == 0
            || iURI->Compare( KVPbkDefaultGrpDbURI ) == 0 )
        {
        iAdaptiveGridMap = CPcsAdaptiveGrid::NewL();
        }
    
    PRINT ( _L("End CPcsCache::ConstructL") );
}

// ----------------------------------------------------------------------------
// CPcsCache::~CPcsCache
// Destructor
// ----------------------------------------------------------------------------
CPcsCache::~CPcsCache()
{
    PRINT ( _L("Enter CPcsCache::~CPcsCache") );

    delete iURI;

    RemoveAllFromCache(); // cleans up iMasterPool and iCacheInfo
   
    iKeyArr.ResetAndDestroy();
    iDataFields.Reset();
    iSortOrder.Reset();
    iIndexOrder.Reset();
    iMasterPoolBackup.Close();

    delete iAdaptiveGridMap;

    PRINT ( _L("End CPcsCache::~CPcsCache") );
}

// ----------------------------------------------------------------------------
// CPcsCache::GetContactsForKeyL
// Get list of pool elements specific to a pool
// ----------------------------------------------------------------------------     
void CPcsCache::GetContactsForKeyL(TInt aKeyId, RPointerArray<CPcsPoolElement>& aData)
    {
    PRINT ( _L("Enter CPcsCache::GetContactsForKeyL") );
    CleanupClosePushL( aData );
    if ( aKeyId >= 0 && aKeyId < iKeyArr.Count() )
        {
        const RPointerArray<CPcsPoolElement>& arr = *iKeyArr[aKeyId];
        for ( TInt i = 0; i < arr.Count(); i++ )
            {
            aData.AppendL(arr[i]);
            }
        }
    CleanupStack::Pop();
    PRINT ( _L("End CPcsCache::GetContactsForKeyL") );
    }

// ----------------------------------------------------------------------------
// CPcsCache::GetAllContentsL
// Get all data elements in this cache
// ----------------------------------------------------------------------------     
void CPcsCache::GetAllContentsL(RPointerArray<CPsData>& aData)
{
    PRINT ( _L("Enter CPcsCache::GetAllContentsL") );
    CleanupClosePushL( aData );	
	for ( TInt i = 0; i < iMasterPool.Count(); i++ )
	{
        aData.AppendL(iMasterPool[i]);
	}
	CleanupStack::Pop();
	PRINT ( _L("End CPcsCache::GetAllContentsL") );
}

// ----------------------------------------------------------------------------
// CPcsCache::AddToPool
// Adds a contact to cache
// ----------------------------------------------------------------------------
void CPcsCache::AddToPoolL(TUint64& aPoolMap, CPsData& aData)
{
    // Temp hash to remember the location of pool elements
    // First TInt  = Pool 
    // Second TInt = Location in the pool
    // Required for memory optimization so that more than one pool
    // element doesn't get added for the same data
    RHashMap<TInt, TInt> elementHash;
    CleanupClosePushL( elementHash );
    TLinearOrder<CPcsPoolElement> rule( CPcsPoolElement::CompareByDataL );

    TBool unnamed = ETrue;
    // Parse thru each data element
    for ( TInt dataIndex = 0; dataIndex < aData.DataElementCount(); dataIndex++ )
    {
        HBufC* dataStr = aData.Data(dataIndex);

        // Find store all the pool IDs where this contact should be
		RArray<TUint> poolIds;
		CleanupClosePushL( poolIds );
		
		// Recover the first character
		if ( dataStr && dataStr->Length() != 0 )
		{
		    // Split the data into words
		    CWords* words = CWords::NewLC(*dataStr);

		    // Store the first numeric key for each word
		    for ( TInt i = 0; i < words->MdcaCount(); i++ )
		    {
		    	TChar firstChar = (words->MdcaPoint(i))[0];
		    	
		    	// Pool ID according to ITU-T mappings
		    	if ( iKeyMap->IsItutPredictiveAvailable() )
		    	    {
                    TInt itutPoolId = iKeyMap->PoolIdForCharacter(firstChar, EPredictiveItuT);
                    if ( itutPoolId != KErrNotFound )
                        {
                        poolIds.Append(itutPoolId);
                        }
		    	    }
		    	
		    	// Pool ID according to QWERTY mappings
                if ( iKeyMap->IsQwertyPredictiveAvailable() )
                    {
                    TInt qwertyPoolId = iKeyMap->PoolIdForCharacter(firstChar, EPredictiveQwerty);
                    if ( qwertyPoolId != KErrNotFound )
                        {
                        poolIds.Append(qwertyPoolId);
                        }
                    }

#ifdef _DEBUG 
                PRINT2 ( _L("CPcsCache::AddToPoolL: iURI=\"%S\", iUriId=%d"), &*iURI, iUriId );
                TPtrC16 ptr = words->MdcaPoint(i); 
                PRINT5 ( _L("CPcsCache::AddToPoolL: Data[%d]=\"%S\", word=\"%S\", firstChar='%c', Match=%d" ),
                         dataIndex, &*dataStr, &(ptr), (TUint) firstChar, aData.IsDataMatch(dataIndex) );
#endif // _DEBUG

                if ( iAdaptiveGridMap )
                	{
					// Set the 1st char of the word for the Adaptive Grid or
					// increment the reference counter
					TUint selector = GridItemSelector( dataIndex, unnamed );
					iAdaptiveGridMap->IncrementRefCounterL( firstChar, selector );
                	}
		    }
		    
		    CleanupStack::PopAndDestroy(words); 
		}
		
		for ( TInt poolIdIndex = 0; poolIdIndex < poolIds.Count(); poolIdIndex++ )
		{
            TUint poolId = poolIds[poolIdIndex];
		    CPcsPoolElement* element = NULL;
		    
		    // Check if an element already exists in the pool for this data
		    TInt* loc = NULL;
		    loc = elementHash.Find(poolId);
		    if ( loc != NULL )
		    {
		        // Exists. Then recover ...
		        const RPointerArray<CPcsPoolElement>& tmpKeyMap = *(iKeyArr[poolId]);
		    	element = tmpKeyMap[*loc];
		    }
		
			if ( element == NULL ) // Pool element doesn't exist. Create new ...
			{
		        element = CPcsPoolElement::NewL(aData);
		        CleanupStack::PushL( element );
		    	element->ClearDataMatchAttribute();
				element->SetDataMatch(dataIndex);
				
				// Insert to pool
				iKeyArr[poolId]->InsertInOrderAllowRepeatsL(element, rule);
				CleanupStack::Pop( element ); // ownership transferred
				TInt index = iKeyArr[poolId]->FindInOrderL(element, rule);
				
				// Set the bit for this pool
				SetPoolMap(aPoolMap, poolId);
				
				// Store the array index in the temp hash
				elementHash.InsertL(poolId, index);
	        }
	        else // Pool element exists. Just alter the data match attribute
	        {
	        	element->SetDataMatch(dataIndex);
	        	
	            // Set the bit for this pool
				SetPoolMap(aPoolMap, poolId);
	        }
			
		} // for 2 loop
		
		CleanupStack::PopAndDestroy( &poolIds );
		
    } // for 1 loop

    CleanupStack::PopAndDestroy( &elementHash );
}

// ---------------------------------------------------------------------
// CPcsCache::AddToCacheL
// 
// ---------------------------------------------------------------------
void CPcsCache::AddToCacheL( CPsData& aData )
{
    // Protect against duplicate items getting added
    if ( iCacheInfo.Find(aData.Id()) != NULL )
    {
        return;
    }
    
    // Include this element in the pool
    TUint64 poolMap = 0;
    AddToPoolL(poolMap, aData);
    iCacheInfo.InsertL(aData.Id(), poolMap);

    // Include this element in master pool
    TLinearOrder<CPsData> rule( CPcsAlgorithm1Utils::CompareDataBySortOrderL );
    
    iMasterPool.InsertInOrderAllowRepeatsL(&aData, rule);
}

// ---------------------------------------------------------------------
// CPcsCache::RemoveContactL
// 
// ---------------------------------------------------------------------
void CPcsCache::RemoveFromCacheL( TInt aItemId )
{
    CPsData* data = NULL;
    
    TUint64* poolMap = iCacheInfo.Find(aItemId);
    
    if ( poolMap == NULL )
    {
    	return;
    }
    
    // Remove this element from pools
    for ( TInt keyIndex = 0; keyIndex < iKeyArr.Count(); keyIndex++ )
    {
        TBool present = GetPoolMap(*poolMap, keyIndex); 

        if ( !present )
        {
        	continue;
        }
        
        TInt arrayIndex = 0;
        TInt arrayCount = iKeyArr[keyIndex]->Count();
        while ( arrayIndex < arrayCount )
        {
            CPcsPoolElement* element = (*(iKeyArr[keyIndex]))[arrayIndex];
            if ( element->GetPsData()->Id() == aItemId )
            {
                data = element->GetPsData();
                delete element;
                iKeyArr[keyIndex]->Remove(arrayIndex);
                arrayCount--;
            }
            else
            {
                arrayIndex++;
            }
        }
    }

    // Remove this element from master pool
    TInt arrayIndex = 0;
    TInt arrayCount = iMasterPool.Count();
    while ( arrayIndex < arrayCount )
    {
        if ( iMasterPool[arrayIndex]->Id() == aItemId )
        {
            iMasterPool.Remove(arrayIndex);
            arrayCount--;
        }
        else
        {
            arrayIndex++;
        }
    }
    
    if ( iAdaptiveGridMap && data )
    {
        TBool unnamed = ETrue;
        // Parse thru each data element
        for ( TInt dataIndex = 0; dataIndex < data->DataElementCount(); dataIndex++ )
        {
            HBufC* dataStr = data->Data(dataIndex);
    
            // Recover the first character
            if ( dataStr && dataStr->Length() != 0 )
            {
                // Split the data into words
                CWords* words = CWords::NewLC(*dataStr);
    
                // Store the first numeric key for each word
                for ( TInt i = 0; i < words->MdcaCount(); i++ )
                {
                    TChar firstChar = (words->MdcaPoint(i))[0];
    
#ifdef _DEBUG
                    PRINT2 ( _L("CPcsCache::RemoveFromCacheL: iURI=\"%S\", iUriId=%d"), &*iURI, iUriId );
                    TPtrC16 ptr = words->MdcaPoint(i); 
                    PRINT5 ( _L("CPcsCache::RemoveFromCacheL: Data[%d]=\"%S\", word=\"%S\", firstChar='%c', Match=%d" ),
                             dataIndex, &*dataStr, &(ptr), (TUint) firstChar, data->IsDataMatch(dataIndex) );
#endif // _DEBUG   
                    // Decrement the reference counter of the 1st char of the word for the Adaptive Grid or
                    // delete the Adaptive Grid item if there are no references to it anymore
                    TUint selector = GridItemSelector( dataIndex, unnamed );
                    iAdaptiveGridMap->DecrementRefCounter( firstChar, selector );
                }
                CleanupStack::PopAndDestroy( words ); 
            }
        }
    }

    // Delete data 
    delete data;
    data = NULL;

    // Clear up cache information
    iCacheInfo.Remove(aItemId);
}

// ---------------------------------------------------------------------
// CPcsCache::RemoveAllFromCache
// 
// ---------------------------------------------------------------------
void CPcsCache::RemoveAllFromCache()
{
    PRINT ( _L("Enter CPcsCache::RemoveAllFromCache") );
    
    for ( TInt i = 0; i < iKeyArr.Count(); i++ )
        {
        iKeyArr[i]->ResetAndDestroy();
        }
	
	iMasterPool.ResetAndDestroy();
	iCacheInfo.Close();

	if ( iAdaptiveGridMap )
	    {
	    iAdaptiveGridMap->Reset();
	    }
	
	PRINT ( _L("End CPcsCache::RemoveAllFromCache") );
}

// ---------------------------------------------------------------------
// CPcsCache::GetAdaptiveGridL
// 
// ---------------------------------------------------------------------
void CPcsCache::GetAdaptiveGridL( const TBool aCompanyName, TDes& aAdaptiveGrid )
{
    PRINT ( _L("Enter CPcsCache::GetAdaptiveGridL") );
    
    if ( iAdaptiveGridMap )
        {
        iAdaptiveGridMap->GetAdaptiveGrid( aCompanyName, aAdaptiveGrid );
        }
    
    PRINT ( _L("End CPcsCache::GetAdaptiveGridL") );
}

// ---------------------------------------------------------------------
// CPcsCache::SetPoolMap
// 
// ---------------------------------------------------------------------
void CPcsCache::SetPoolMap(TUint64& aPoolMap, TInt aArrayIndex)
{
    __ASSERT_DEBUG( aArrayIndex < 64, User::Panic(_L("CPcsCache"), KErrOverflow ) );

    /* Some platforms do not support 64 bits shift operations.
     * Split to two 32 bits operations.
     */
    
    TUint32 poolMapH = I64HIGH(aPoolMap);
    TUint32 poolMapL = I64LOW(aPoolMap);
    
    TUint32 valH = 0;
    TUint32 valL = 0;
    if (aArrayIndex < 32)
        {
        valL = 1 << aArrayIndex;
        }
    else
        {
        valH = 1 << (aArrayIndex-32);
        }

    poolMapH |= valH;
    poolMapL |= valL;
    
    aPoolMap = MAKE_TUINT64(poolMapH, poolMapL);
}

// ---------------------------------------------------------------------
// CPcsCache::GetPoolMap
// 
// ---------------------------------------------------------------------
TBool CPcsCache::GetPoolMap(TUint64& aPoolMap, TInt aArrayIndex)
{
    __ASSERT_DEBUG( aArrayIndex < 64, User::Panic(_L("CPcsCache"), KErrOverflow ) );

    /* Some platforms do not support 64 bits shift operations.
     * Split to two 32 bits operations.
     */

    TUint32 poolMapH = I64HIGH(aPoolMap);
    TUint32 poolMapL = I64LOW(aPoolMap);
    
    TUint32 valH = 0;
    TUint32 valL = 0;
    if (aArrayIndex < 32)
        {
        valL = 1 << aArrayIndex;
        }
    else
        {
        valH = 1 << (aArrayIndex-32);
        }

    TBool ret = (poolMapH & valH) || (poolMapL & valL);

    return (ret);
}

// ---------------------------------------------------------------------
// CPcsCache::GetURI
// 
// ---------------------------------------------------------------------
TDesC& CPcsCache::GetURI()
{
	return (*iURI);
}

// ---------------------------------------------------------------------
// CPcsCache::SetDataFields
// 
// ---------------------------------------------------------------------
void CPcsCache::SetDataFields(RArray<TInt>& aDataFields)
{
	for (TInt i(0); i < aDataFields.Count(); i++)
	{
		iDataFields.Append(aDataFields[i]);
	}
}

// ---------------------------------------------------------------------
// CPcsCache::GetDataFields
// 
// ---------------------------------------------------------------------
void CPcsCache::GetDataFields(RArray<TInt>& aDataFields)
{
	for (TInt i(0); i < iDataFields.Count(); i++)
	{
		aDataFields.Append(iDataFields[i]);
	}
}

// ---------------------------------------------------------------------
// CPcsCache::UpdateCacheStatus
// 
// ---------------------------------------------------------------------
void CPcsCache::UpdateCacheStatus(TInt aStatus)
{
	iCacheStatus = aStatus;
}

// ---------------------------------------------------------------------
// CPcsCache::GetCacheStatus
// 
// ---------------------------------------------------------------------
TInt CPcsCache::GetCacheStatus()
{
	return iCacheStatus;
}

// ---------------------------------------------------------------------
// CPcsCache::GetUriId
// 
// ---------------------------------------------------------------------
TUint8 CPcsCache::GetUriId()
{
	return iUriId;
}

// ---------------------------------------------------------------------
// CPcsCache::SetSortOrder
// 
// ---------------------------------------------------------------------
void CPcsCache::SetSortOrder(RArray<TInt>& aSortOrder)
{
    PRINT ( _L("Enter CPcsCache::SetSortOrder") );    
    
    iSortOrder.Reset();
    
	for (TInt i(0); i < aSortOrder.Count(); i++)
	{
		iSortOrder.Append(aSortOrder[i]);
	}
	
	ComputeIndexOrder();
	
	PRINT ( _L("End CPcsCache::SetSortOrder") );
}

// ---------------------------------------------------------------------
// CPcsCache::GetSortOrder
// 
// ---------------------------------------------------------------------
void CPcsCache::GetSortOrder(RArray<TInt>& aSortOrder)
{
    aSortOrder.Reset();
    
	for (TInt i(0); i < iSortOrder.Count(); i++)
	{
		aSortOrder.Append(iSortOrder[i]);
	}	
}

// ---------------------------------------------------------------------
// CPcsCache::GetIndexOrder
// 
// ---------------------------------------------------------------------
void CPcsCache::GetIndexOrder(RArray<TInt>& aIndexOrder)
{   
    aIndexOrder.Reset();
    
	for (TInt i(0); i < iIndexOrder.Count(); i++)
	{
		aIndexOrder.Append(iIndexOrder[i]);
	}	
}

// ---------------------------------------------------------------------
// CPcsCache::ComputeIndexOrder
// 
// ---------------------------------------------------------------------
void CPcsCache::ComputeIndexOrder()
{   
    iIndexOrder.Reset();
    
	for ( TInt i = 0; i < iSortOrder.Count(); i++ )
	{
		for ( TInt j = 0; j < iDataFields.Count(); j++ )
		{
			if ( iSortOrder[i] == iDataFields[j] )
			{
				iIndexOrder.Append(j);
				break;
			}
		}
	}
}

// ---------------------------------------------------------------------
// CPcsCache::ResortdataInPools
// 
// ---------------------------------------------------------------------
void CPcsCache::ResortdataInPoolsL()
    {
    // Copy iMasterPool data into iMasterPoolBackup
    for (TInt i = 0; i < iMasterPool.Count(); i++ )
        {
        iMasterPoolBackup.Append( iMasterPool[i] );
        }

    // Now reset the key array
    for (TInt i = 0; i < iKeyArr.Count(); i++ )
        {
        iKeyArr[i]->ResetAndDestroy();
        }
    iMasterPool.Reset();
    iCacheInfo.Close();
    if ( iAdaptiveGridMap )
        {
        iAdaptiveGridMap->Reset();
        }
    
    // Now add data again from the iMasterPoolBackup
    for (TInt i = 0; i < iMasterPoolBackup.Count(); i++ )
        {
        CPsData* temp = iMasterPoolBackup[i];
        AddToCacheL( *temp );
        }
    iMasterPoolBackup.Reset();
    }

// ---------------------------------------------------------------------
// CPcsCache::GridItemSelectorL
// 
// ---------------------------------------------------------------------
TUint CPcsCache::GridItemSelector( TInt aIndex, TBool& aUnnamed )
    {
    __ASSERT_ALWAYS( iDataFields.Count() > aIndex, User::Panic(_L("CPcsCache"), KErrArgument ) );

    if ( iDataFields[aIndex] == R_VPBK_FIELD_TYPE_LASTNAME || iDataFields[aIndex] == R_VPBK_FIELD_TYPE_FIRSTNAME )
        {
        aUnnamed = EFalse;
        return CPcsAdaptiveGridItem::EFirstNameLastName;
        }
    else if ( iDataFields[aIndex] == R_VPBK_FIELD_TYPE_COMPANYNAME && !aUnnamed )
        {
        return CPcsAdaptiveGridItem::ECompanyName;
        }
    else if ( iDataFields[aIndex] == R_VPBK_FIELD_TYPE_COMPANYNAME )
        {
        return CPcsAdaptiveGridItem::EUnnamedCompanyName;
        }
    else
        {
        return CPcsAdaptiveGridItem::ENumberCounters;
        }
    }

// End of file