predictivesearch/PcsAlgorithm/Algorithm1/src/CPcsAlgorithm1.cpp
changeset 0 e686773b3f54
child 6 e8e3147d53eb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/predictivesearch/PcsAlgorithm/Algorithm1/src/CPcsAlgorithm1.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1544 @@
+/*
+* 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:  Predictive Contact Search Algorithm 1 main class
+*
+*/
+
+
+// INCLUDES
+#include "CPcsAlgorithm1.h"
+#include "CPcsAlgorithm1Helper.h"
+#include "CPcsAlgorithm1MultiSearchHelper.h"
+#include "CPcsAlgorithm1Utils.h"
+#include "CPcsDebug.h"
+#include "CPcsCache.h"
+#include "CPcsKeyMap.h"
+#include "CPsData.h"
+#include "CWords.h"
+#include "CPsQuery.h"
+#include "CPsDataPluginInterface.h"
+#include "CPcsDefs.h"
+
+const TInt KSpace = 32;
+
+// UID used for Publish and Subscribe mechanism
+// This should be same as the one defined in CPsPropertyHandler.cpp
+const TUid KCStatus = {0x2000B5B6};
+
+// ============================== MEMBER FUNCTIONS ============================
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::NewL
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+CPcsAlgorithm1* CPcsAlgorithm1::NewL()
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::NewL") );
+    
+	CPcsAlgorithm1* self = new ( ELeave ) CPcsAlgorithm1();
+	CleanupStack::PushL( self );
+	self->ConstructL();
+	CleanupStack::Pop( self );
+
+    PRINT ( _L("End CPcsAlgorithm1::NewL") );
+    
+	return self;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::CPcsAlgorithm1
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+CPcsAlgorithm1::CPcsAlgorithm1()
+{		
+    PRINT ( _L("Enter CPcsAlgorithm1::CPcsAlgorithm1") );
+    PRINT ( _L("End CPcsAlgorithm1::CPcsAlgorithm1") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ConstructL
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::ConstructL()
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::ConstructL") );
+    
+    iCacheStatus = ECachingNotStarted;  // Starting status
+    iCacheError = KErrNone;             // No error
+    iCacheCount = 0;                    // No data
+        
+    iPluginLauncher = CIdle::NewL( CActive::EPriorityStandard );
+    
+    // Define cache status property used to inform clients about the caching status.
+    TInt err = RProperty::Define(KCStatus,0, RProperty::EInt);      
+    if ( err != KErrAlreadyExists )
+    {
+    	User::LeaveIfError(err);
+    }
+    
+    // Define cache error property used to inform client about the errors.
+    err = RProperty::Define(KCStatus,1, RProperty::EInt);
+    if ( err != KErrAlreadyExists )
+    {
+    	User::LeaveIfError(err);
+    }
+    
+    // Initialize key map and pti engine
+    //keyMap = CPcsKeyMap::NewL();
+    TInt keyMapErr = KErrNone;
+    TRAP( keyMapErr, iKeyMap = CPcsKeyMap::NewL());
+    if ( keyMapErr != KErrNone )
+    {
+    PRINT ( _L("**********************************************."));
+    PRINT1 ( _L("CPcsAlgorithm1::ConstructL() KeyMap construction error. The keymap crashed with error code %d."),keyMapErr );
+    PRINT ( _L("Please check the keypad/language for which keymap got crashed.") );
+    PRINT ( _L("**********************************************."));
+    }
+    
+    // Initialize helpers
+    iHelper = CPcsAlgorithm1Helper::NewL(this);
+    iMultiSearchHelper = CPcsAlgorithm1MultiSearchHelper::NewL(this);
+    
+    if(!iPluginLauncher->IsActive())
+        {
+        iPluginLauncher->Start(TCallBack(CPcsAlgorithm1::DoLaunchPluginsL, this));
+        }
+     
+    PRINT ( _L("End CPcsAlgorithm1::ConstructL") );
+} 
+	
+	
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::~CPcsAlgorithm1
+// Destructor
+// ----------------------------------------------------------------------------
+CPcsAlgorithm1::~CPcsAlgorithm1()
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::~CPcsAlgorithm1") );
+    
+    // Clear TLS
+    Dll::SetTls(NULL);
+    
+    // Cleanup cache
+    iPcsCache.ResetAndDestroy();
+    
+    // Cleanup adapters interface and key handling
+    delete iKeyMap;
+    delete iPsDataPluginInterface;
+    
+    // Cleanup helpers
+    delete iHelper;
+    delete iMultiSearchHelper;
+    
+    delete iPluginLauncher;
+
+    PRINT ( _L("End CPcsAlgorithm1::~CPcsAlgorithm1") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveSpacesL
+// Remove leading and trailing spaces of search query
+// ----------------------------------------------------------------------------
+void  CPcsAlgorithm1::RemoveSpacesL(CPsQuery& aQuery)
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::RemoveSpacesL") );
+
+    //PRINTQUERY ( _L("CPcsAlgorithm1::RemoveSpacesL (BEFORE): "), aQuery );
+
+    // Remove all leading " "
+    while ( aQuery.Count() > 0 )
+    {
+        CPsQueryItem& item = aQuery.GetItemAtL(0); // First
+        if ( !item.Character().IsSpace() )
+        {
+            break;
+        }
+        aQuery.Remove(0);
+    }
+
+    // Remove all trailing " "
+    while ( aQuery.Count() > 0 )
+    {
+        CPsQueryItem& item = aQuery.GetItemAtL(aQuery.Count()-1); // Last
+        if ( !item.Character().IsSpace() )
+        {
+            break;
+        }
+        aQuery.Remove(aQuery.Count()-1);
+    }
+    
+    //PRINTQUERY ( _L("CPcsAlgorithm1::RemoveSpacesL (AFTER): "), aQuery );
+    
+    PRINT ( _L("End CPcsAlgorithm1::RemoveSpacesL") );
+}    
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ReplaceZeroWithSpaceL
+// Replace all '0's in a search query with " "s
+// ----------------------------------------------------------------------------
+TBool  CPcsAlgorithm1::ReplaceZeroWithSpaceL(CPsQuery& aQuery)
+{   
+    PRINT ( _L("Enter CPcsAlgorithm1::ReplaceZeroWithSpaceL") );
+
+    //PRINTQUERY ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL (BEFORE): "), aQuery );
+
+    TBool queryModified = EFalse;    
+
+    if (iKeyMap->GetSpaceAndZeroOnSameKey())
+    {
+        /* In phones like E52 and E55, where the "0" and the " " characters are on
+         * the same key, then the "0"s EItut have to be considered as possible
+         * separators.
+         */
+
+        // Skip initial "0"s, they are not replaced into spaces
+        TInt skipIndex = 0;
+        while ( (skipIndex < aQuery.Count()) && 
+                (aQuery.GetItemAtL(skipIndex).Character().GetNumericValue() == 0) )
+        {
+            skipIndex++;
+        }
+        
+        // Replace remaining EItut "0"s into spaces
+        TChar space(KSpace);    
+        for ( TInt index = skipIndex; index < aQuery.Count(); index++ )
+        {
+            CPsQueryItem& item = aQuery.GetItemAtL(index);
+    
+            if ( item.Character().GetNumericValue() == 0 &&
+                 item.Mode() == EItut )
+            {
+                item.SetCharacter(space);
+                queryModified = ETrue;
+            }
+        }    
+    }
+    else
+    {
+        /* In phones like N97 and E72, where the "0" and the " " characters are on
+         * a different key, then the "0" EItut does not have to be considered as a
+         * possible separator.
+         */
+        
+        PRINT ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL: \"0\" and \" \" are on different keys, not attepting to replace") );
+    }
+    
+    //PRINTQUERY ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL (AFTER): "), aQuery );
+
+    PRINT1 ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL: Query modified (0=not, 1=yes): %d"), queryModified );
+
+    PRINT ( _L("End CPcsAlgorithm1::ReplaceZeroWithSpaceL") );
+
+    return  queryModified;
+}  
+   
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::PerformSearchL
+// Search function for cache
+// ----------------------------------------------------------------------------
+void  CPcsAlgorithm1::PerformSearchL(const CPsSettings& aSettings,
+                                     CPsQuery& aQuery,
+                                     RPointerArray<CPsClientData>& aSearchResults,
+                                     RPointerArray<CPsPattern>& aSearchSeqs)                                    
+{
+	PRINT ( _L("Enter CPcsAlgorithm1::PerformSearchL") );
+	
+	__LATENCY_MARK ( _L("CPcsAlgorithm1::PerformSearchL") );
+
+	RPointerArray<CPsQuery> query;
+	
+	// Local arrays to hold the search results 
+	RPointerArray<CPsData> tempSearchResults;
+    RPointerArray<CPsData> tempSearchResultsIni;
+    RPointerArray<CPsData> tempSearchResultsMod;
+
+    // ----------------------- Perform the basic search -----------------------
+	/* Even before replacing zeroes with spaces the query can have multiple words
+	 * Some phones support infact double keyboards with possibility to type a space in qwerty mode
+	 * A space in qwerty mode can even be typed disabling temporarily PCS
+	 */
+    RemoveSpacesL(aQuery);
+    PRINTQUERY ( _L("CPcsAlgorithm1::PerformSearchL: 1st search query: "), aQuery );
+	DoSearchL(aSettings, aQuery, tempSearchResultsIni, aSearchSeqs );
+    // ------------------------------------------------------------------------
+
+    // ---- Perform new search after "0" replacement if query is not empty ----
+    /* Examples:
+     * - If the original search string is "Abc0" then we will search again with "Abc".
+     * - If the original search string is "00" then we will not search again.
+     * - If the original search string is "00Zxc" then we will search again with "Zxc".
+     */
+    TBool isQueryModified = ReplaceZeroWithSpaceL(aQuery);
+    RemoveSpacesL(aQuery);
+    if ( isQueryModified && (aQuery.Count() > 0) )
+    {
+        PRINTQUERY ( _L("CPcsAlgorithm1::PerformSearchL: 2nd search query: "), aQuery );
+        DoSearchL(aSettings, aQuery, tempSearchResultsMod, aSearchSeqs );
+    }
+    // ------------------------------------------------------------------------
+
+    // ------------------ Merge and sort the search results -------------------
+	if ( tempSearchResultsIni.Count() + tempSearchResultsMod.Count() > 0)
+	{
+		// Sort rule        
+		TLinearOrder<CPsData> rule( CPcsAlgorithm1Utils::CompareDataBySortOrderL );
+
+		// Avoid duplicates and add new results
+		TIdentityRelation<CPsData> identityRule(CPsData::CompareById);
+
+        for ( TInt i = 0; i < tempSearchResultsIni.Count(); i++ )
+        {
+            if ( tempSearchResults.Find( tempSearchResultsIni[i],identityRule ) == KErrNotFound )
+            {
+                if (aSettings.GetSortType() == EAlphabetical)
+                {
+                    tempSearchResults.InsertInOrderAllowRepeats(tempSearchResultsIni[i], rule);
+                }
+                else
+                {
+                    tempSearchResults.AppendL(tempSearchResultsIni[i]);
+                }
+            }
+        }
+
+        for ( TInt i = 0; i < tempSearchResultsMod.Count(); i++ )
+        {
+            if ( tempSearchResults.Find( tempSearchResultsMod[i],identityRule ) == KErrNotFound )
+            {
+                if (aSettings.GetSortType() == EAlphabetical)
+                {
+                    tempSearchResults.InsertInOrderAllowRepeats(tempSearchResultsMod[i], rule);
+                }
+                else
+                {
+                    tempSearchResults.AppendL(tempSearchResultsMod[i]);
+                }
+            }
+        }
+	}
+	// ------------------------------------------------------------------------
+
+    // ------------------ Write result objects to the stream ------------------
+	// Truncate the result set if required
+	TInt numToDisplay = aSettings.MaxResults();
+	TInt resultSet = tempSearchResults.Count();
+	
+	if( resultSet > numToDisplay && numToDisplay != -1)
+	{
+		// Copy the top N contents from tempSearchResults to the results stream
+		for(int i = 0; i < numToDisplay; i++)
+		{
+			aSearchResults.Append(WriteClientDataL(*(tempSearchResults[i])));
+		}
+	}
+	else
+	{
+		// Copy all the contents from tempSearchResults to the results stream
+		for(int i = 0; i < resultSet; i++)
+		{
+			aSearchResults.Append(WriteClientDataL(*(tempSearchResults[i])));
+		}
+	}
+	// ------------------------------------------------------------------------
+
+    // Cleanup local results array
+	tempSearchResults.Reset();    // Don't destroy
+    tempSearchResultsIni.Reset(); // Don't destroy
+    tempSearchResultsMod.Reset(); // Don't destroy
+
+	__LATENCY_MARKEND ( _L("CPcsAlgorithm1::PerformSearchL") );
+
+	PRINT ( _L("End CPcsAlgorithm1::PerformSearchL") );			
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::SearchInputL
+// Search function for input string
+// ----------------------------------------------------------------------------
+void  CPcsAlgorithm1::SearchInputL(CPsQuery& aQuery,
+                                   TDesC& aData,
+                                   RPointerArray<TDesC>& aMatchSet,
+                                   RArray<TPsMatchLocation>& aMatchLocation )
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::SearchInputL") );
+
+    __LATENCY_MARK ( _L("CPcsAlgorithm1::SearchInputL") ); 
+
+    // ----------------------- Perform the basic search -----------------------
+    /* Even before replacing zeroes with spaces the query can have multiple words
+     * Some phones support infact double keyboards with possibility to type a space in qwerty mode
+     * A space in qwerty mode can even be typed disabling temporarily PCS
+     */
+    RemoveSpacesL(aQuery);
+    DoSearchInputL(aQuery, aData, aMatchSet, aMatchLocation);
+    PRINTQUERY    ( _L("CPcsAlgorithm1::SearchInputL: 1st search: "), aQuery );
+    PRINT1        ( _L("CPcsAlgorithm1::SearchInputL: 1st search: Search Data: %S"), &aData );
+    PRINTMATCHSET ( _L("CPcsAlgorithm1::SearchInputL: 1st search: "), aMatchSet );
+    PRINTMATCHLOC ( _L("CPcsAlgorithm1::SearchInputL: 1st search: "), aMatchLocation );
+    // ------------------------------------------------------------------------
+    
+    // ---- Perform new search after "0" replacement if query is not empty ----
+    /* Examples:
+     * - If the original search string is "Abc0" then we will search again with "Abc".
+     * - If the original search string is "00" then we will not search again.
+     */
+    TBool isQueryModified = ReplaceZeroWithSpaceL(aQuery);
+    RemoveSpacesL(aQuery);
+    if ( isQueryModified && (aQuery.Count() > 0) )
+    {
+        DoSearchInputL(aQuery, aData, aMatchSet, aMatchLocation);
+        PRINTQUERY    ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: "), aQuery );
+        PRINT1        ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: Search Data: %S"), &aData );
+        PRINTMATCHSET ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: "), aMatchSet );
+        PRINTMATCHLOC ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: "), aMatchLocation );
+    }
+    /* In cases like we have a contact "Nik0 Abc" and the search query is "Nik0" we do:
+     * - a 1st search with "Nik0" that matches "Nik0" (4 chars) of "Nik0 Abc",
+     * - a 2nd search with "Nik" that matches "Nik" (3 chars) of "Nik0 Abc".
+     * We have to remove from aMatchLocation the occurrence that has a shorter match length.
+     * We have to remove the match ("Nik" in this case) even from aMatchSet if there is not
+     * any other match for it than the one in "Nik0".
+     */
+
+    // --- Remove items from aMatchLocation ---
+    TInt i = 0;
+    TBool incrementFirstCursor;
+    while ( i < aMatchLocation.Count() )
+    {
+        incrementFirstCursor = ETrue;
+        TInt j = i+1;
+        while ( j < aMatchLocation.Count() )
+        {
+            if (aMatchLocation[j].index == aMatchLocation[i].index)
+            {
+                // Remove match location item with smallest length if 2 items have same index
+                if ( aMatchLocation[j].length <= aMatchLocation[i].length )
+                {
+                    aMatchLocation.Remove(j);
+                    continue; // Do not increment j
+                }
+                else
+                {
+                    aMatchLocation.Remove(i);
+                    incrementFirstCursor = EFalse; // Do not increment i
+                    break;
+                }
+            }
+            j++;
+        }
+        if ( incrementFirstCursor )
+        {
+            i++;
+        }
+    }
+
+    // --- Remove items from aMatchSet ---
+    HBufC* dataUpper = HBufC::NewLC(aData.Length());
+    dataUpper->Des().Copy(aData);
+    dataUpper->Des().UpperCase(); // Get uppercase, as aMatchSet is in upper case
+
+    TInt k = 0;
+    while ( k < aMatchSet.Count() )
+    {
+        TBool keepMatch = EFalse;
+        TInt startCursor = -1;
+
+        TInt offsetCursor;
+        while ( KErrNotFound != (offsetCursor = dataUpper->Mid(startCursor + 1).Find(*aMatchSet[k])) )
+        {
+            // startCursor = index of match item *aMatchSet[k] into search string aData
+            startCursor = offsetCursor + startCursor + 1;
+            for ( TInt i = 0; i < aMatchLocation.Count(); i++ )
+            {
+                // If match item was found in the location list, then keep it
+                if ( (aMatchLocation[i].index == startCursor) &&
+                     (aMatchLocation[i].length == aMatchSet[k]->Length()) )
+                {
+                    keepMatch = ETrue;
+                    break;
+                }
+            }
+        }
+
+        if ( keepMatch )
+        {
+            k++;
+        }
+        else
+        {
+            aMatchSet.Remove(k); // Do not increment k
+        }
+        // --- Remove items End ---
+
+    }
+    CleanupStack::PopAndDestroy( dataUpper );
+    // ------------------------------------------------------------------------
+
+    // Sort match set
+	iHelper->SortSearchSeqsL(aMatchSet);  
+	
+    PRINTQUERY    ( _L("CPcsAlgorithm1::SearchInputL: Final: "), aQuery );
+    PRINT1        ( _L("CPcsAlgorithm1::SearchInputL: Final: Search Data: %S"), &aData );
+    PRINTMATCHSET ( _L("CPcsAlgorithm1::SearchInputL: Final: "), aMatchSet );
+    PRINTMATCHLOC ( _L("CPcsAlgorithm1::SearchInputL: Final: "), aMatchLocation );
+	
+	__LATENCY_MARKEND ( _L("CPcsAlgorithm1::SearchInputL") );
+
+    PRINT ( _L("End CPcsAlgorithm1::SearchInputL") );			
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::SearchMatchStringL
+// Search function for input string, result also as string
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::SearchMatchStringL( CPsQuery& aSearchQuery,
+                            TDesC& aSearchData,
+                            TDes& aMatch )
+    {
+    PRINT ( _L("Enter CPcsAlgorithm1::SearchMatchStringL") );
+
+    __LATENCY_MARK ( _L("CPcsAlgorithm1::SearchMatchStringL") ); 
+    
+    // ---------------------- Perform the initial search ----------------------
+    iMultiSearchHelper->LookupMatchL( aSearchQuery, aSearchData, aMatch );
+    PRINTQUERY ( _L("CPcsAlgorithm1::SearchMatchStringL: 1st search: "), aSearchQuery );
+    PRINT1     ( _L("CPcsAlgorithm1::SearchMatchStringL: 1st search: Search Data: %S"), &aSearchData );
+    PRINT1     ( _L("CPcsAlgorithm1::SearchMatchStringL: 1st search: Result: %S"), &aMatch );
+    // ------------------------------------------------------------------------
+    
+    // ---- Perform new search after "0" replacement if query is not empty ----
+    /* Examples:
+     * - If the original search string is "Abc0" then we will search again with "Abc".
+     * - If the original search string is "00" then we will not search again.
+     */
+    if ( aMatch.Length() <= 0 )
+    {
+        TBool isQueryModified = ReplaceZeroWithSpaceL(aSearchQuery);
+        if ( isQueryModified && (aSearchQuery.Count() > 0) )
+        {
+            iMultiSearchHelper->LookupMatchL( aSearchQuery, aSearchData, aMatch );
+            PRINTQUERY ( _L("CPcsAlgorithm1::SearchMatchStringL: 2nd search: "), aSearchQuery );
+            PRINT1     ( _L("CPcsAlgorithm1::SearchMatchStringL: 2nd search: Search Data: %S"), &aSearchData );
+            PRINT1     ( _L("CPcsAlgorithm1::SearchMatchStringL: 2nd search: Result: %S"), &aMatch );            
+        }
+    }
+    
+    __LATENCY_MARKEND ( _L("CPcsAlgorithm1::SearchMatchStringL") );
+
+    PRINT ( _L("End CPcsAlgorithm1::SearchMatchStringL") );
+    }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::DoSearchL
+// Search function helper
+// ----------------------------------------------------------------------------
+void  CPcsAlgorithm1::DoSearchL(const CPsSettings& aSettings,
+								CPsQuery& aQuery,
+								RPointerArray<CPsData>& searchResults,
+								RPointerArray<CPsPattern>& searchSeqs )
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::DoSearchL") );
+
+    __LATENCY_MARK ( _L("CPcsAlgorithm1::DoSearchL") ); 
+    
+    // -(0)----------------- Check if group search is required ---------------    
+    RArray<TInt> contactsInGroup;
+    RArray<TInt> groupIdArray;
+    
+    // Create a new settings instance
+    CPsSettings *tempSettings = aSettings.CloneL();
+    
+    TBool isGroupSearch = IsGroupSearchL(*tempSettings, groupIdArray);
+    
+    if ( isGroupSearch )
+    {    
+    	// Replace groups URI with contacts DB URI in new search settings
+    	ReplaceGroupsUriL(*tempSettings);
+        	
+        // List of contacts in this group	
+    	GetContactsInGroupL ( groupIdArray[0], contactsInGroup );
+    }
+    
+   	groupIdArray.Close();
+   	
+    // -----------------------------------------------------------------------
+        
+    // Extract query list. 
+    RPointerArray<CPsQuery> queryList = iMultiSearchHelper->MultiQueryL(aQuery);
+    PRINTQUERYLIST ( _L("CPcsAlgorithm1::DoSearchL: "), queryList );
+
+    // (1)-------------------- No query return all contacts -------------------    
+    if ( queryList.Count() == 0 )
+    {
+    	GetAllContentsL(*tempSettings, searchResults);   
+    	
+    	if ( isGroupSearch ) 
+    	{
+    		FilterSearchResultsForGroupsL ( contactsInGroup, searchResults );
+    	}
+    }
+    // ------------------------------------------------------------------------
+
+    // (2)-------------------- Perform a single query search ------------------
+    else if ( queryList.Count() == 1 ) // single qwery
+    {
+        PRINT ( _L("CPcsAlgorithm1::DoSearchL: Query received is Single. Performing a SingleSearch") );
+
+        iHelper->SearchSingleL(*tempSettings, *queryList[0], isGroupSearch,
+                               contactsInGroup, searchResults, searchSeqs);
+    }
+    // ------------------------------------------------------------------------
+
+    // (3)-------------------- Perform a multi query search -------------------
+    else // multiple query
+    {
+    	PRINT ( _L("CPcsAlgorithm1::DoSearchL: Query received is Multiple. Performing a MultiSearch") );
+
+		// Search results
+		iMultiSearchHelper->SearchMultiL(*tempSettings, queryList, isGroupSearch,
+		                                 contactsInGroup, searchResults, searchSeqs);
+    }
+    // -------------------------------------------------------------------------
+
+    // Cleanup
+    delete tempSettings;
+    tempSettings = NULL;
+    
+    groupIdArray.Close();
+    contactsInGroup.Close();
+	queryList.ResetAndDestroy();
+
+	__LATENCY_MARKEND ( _L("CPcsAlgorithm1::DoSearchL") );
+
+	PRINT ( _L("End CPcsAlgorithm1::DoSearchL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::DoSearchInputL
+// Search function helper
+// ----------------------------------------------------------------------------
+void  CPcsAlgorithm1::DoSearchInputL(CPsQuery& aQuery,
+		                             TDesC& aData,
+		                             RPointerArray<TDesC>& aMatchSet,
+		                             RArray<TPsMatchLocation>& aMatchLocation )
+{
+
+    PRINT ( _L("Enter CPcsAlgorithm1::DoSearchInputL") );
+
+    TInt queryWords = iMultiSearchHelper->CountMultiQueryWordsL(aQuery);
+
+    // No query    
+    if ( queryWords == 0 )
+    {
+    	PRINT ( _L("CPcsAlgorithm1::DoSearchInputL: Query received is empty") );
+    	return;
+    }
+    
+    RPointerArray<CPsQuery> queryList = iMultiSearchHelper->MultiQueryL(aQuery);
+    
+    PRINTQUERYLIST ( _L("CPcsAlgorithm1::DoSearchInputL: "), queryList );
+
+    if ( queryList.Count() == 1 ) // Single query
+    {
+        PRINT ( _L("CPcsAlgorithm1::DoSearchInputL: Query received is single. Performing a single search.") );
+        iHelper->SearchMatchSeqL(aQuery, 
+                             	 aData, 
+                              	 aMatchSet,
+                             	 aMatchLocation);
+    }
+    else // multiple query
+    {
+    	PRINT ( _L("CPcsAlgorithm1::DoSearchInputL: Query received is Multiple. Performing a MultiSearch") );
+    	iMultiSearchHelper->SearchMatchSeqMultiL(queryList, 
+		                                         aData,
+		                                         aMatchSet,
+		                                         aMatchLocation);
+    }
+
+	// Delete all the query elements
+	queryList.ResetAndDestroy();
+
+	PRINT ( _L("End CPcsAlgorithm1::DoSearchInputL") );
+}    
+    
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::AddData
+// Add a data element to the pool
+// ----------------------------------------------------------------------------    
+void CPcsAlgorithm1::AddData(TDesC& aDataStore, CPsData* aData)
+{
+    TInt arrayIndex = GetCacheIndex(aDataStore);
+    
+    if ( arrayIndex < 0 ) return;
+	
+	CPcsCache* cache = iPcsCache[arrayIndex];
+	
+	// Fill the data store index
+	TInt dataStoreIndex = FindStoreUri(aDataStore);
+    if ( dataStoreIndex >= 0 )
+    {
+    	aData->SetUriId(dataStoreIndex);
+    }
+    else 
+    {
+    	PRINT(_L("CPcsAlgorithm1::AddDataL Unknown data store"));
+    	return;
+    }
+    
+	TRAPD(err, cache->AddToCacheL(*aData));
+	
+	if ( err != KErrNone )
+	{
+		SetCachingError(aDataStore, err);
+	}
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveData
+// Remove a data element from the pool
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::RemoveData(TDesC &aDataStore, TInt aItemId)
+{
+    TInt arrayIndex = GetCacheIndex(aDataStore);
+    
+    if ( arrayIndex < 0 ) return;
+	
+	CPcsCache* cache = iPcsCache[arrayIndex];
+	
+	TRAPD(err, cache->RemoveFromCacheL(aItemId));
+	
+	if ( err != KErrNone )
+	{
+		SetCachingError(aDataStore, err);
+	}
+}
+
+// ---------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveAll
+// Remove all the contacts from a datastore
+// ---------------------------------------------------------------------
+void CPcsAlgorithm1::RemoveAll(TDesC& aDataStore)
+{
+	TInt dataStoreIndex = GetCacheIndex(aDataStore);
+	
+	if(dataStoreIndex < 0) return;
+	
+    CPcsCache* cache = iPcsCache[dataStoreIndex];
+    	
+	TRAPD(err, cache->RemoveAllFromCacheL());
+	
+	if ( err != KErrNone )
+	{
+		SetCachingError(aDataStore, err);
+	}
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetCacheIndex
+// Return the cache index for a data store
+// ----------------------------------------------------------------------------
+TInt CPcsAlgorithm1::GetCacheIndex(TDesC& aDataStore)
+{
+    for ( int i = 0; i < iPcsCache.Count(); i++ )
+    {
+    	CPcsCache* cache = iPcsCache[i];
+    	
+    	if ( cache->GetURI().CompareC(aDataStore) == 0 ) return i;
+    }
+    
+	return -1;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::AddDataStore
+// Adds a new store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::AddDataStore(TDesC& aDataStore)
+{
+    // Check if the datastore cache already exists
+    TInt index = GetCacheIndex(aDataStore);
+    if ( index != -1 )
+    {
+    	// Already exists
+    	return;
+    }
+    
+    // Create a new cache    
+    CPcsCache* cache = NULL;
+	TRAPD(err, cache = CPcsCache::NewL(aDataStore, *iKeyMap, iCacheCount));
+	if ( err != KErrNone )
+	{
+		SetCachingError(aDataStore, err);
+		return;
+	}	
+	
+	// Increment the cachecount
+	iCacheCount++;
+	
+    RArray<TInt> dataFields;        	   
+    TRAP(err, iPsDataPluginInterface->GetSupportedDataFieldsL(cache->GetURI(), dataFields));   
+	if ( err != KErrNone )
+	{
+		SetCachingError(aDataStore, err);
+		return;
+	}		    
+    cache->SetDataFields(dataFields); 
+    
+    // Check if sort order is persisted already    
+    RArray<TInt> sortOrder;
+    TRAP(err, ReadSortOrderFromCenRepL(*(cache->GetUri()), sortOrder));
+    if ( err != KErrNone )
+	{
+		SetCachingError(aDataStore, err);
+		return;
+	}
+    
+    if ( sortOrder.Count() == 0 )
+    {
+    	cache->SetSortOrder(dataFields); // Initial sort order	
+    }
+    else 
+    {
+    	cache->SetSortOrder(sortOrder); // Persisted sort order
+    }
+    
+    sortOrder.Close();
+    dataFields.Close();
+    
+    iPcsCache.Append(cache);
+    
+	TRAP(err, iPsDataPluginInterface->RequestForDataL(aDataStore));
+	if ( err != KErrNone )
+	{
+		PRINT ( _L("CPcsAlgorithm1::AddDataStore() Set Caching Error ") );
+		SetCachingError(aDataStore, err);
+		UpdateCachingStatus(aDataStore,ECachingCompleteWithErrors);
+		return;
+	}		
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveDataStore
+// Removes an existing data store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::RemoveDataStore(TDesC& aDataStore)
+{
+    for ( int i = 0; i < iPcsCache.Count(); i++ )
+    {
+    	CPcsCache* cache = iPcsCache[i];
+    	
+    	if ( cache->GetURI().CompareC(aDataStore) == 0 ) 
+    	{
+    		delete iPcsCache[i];
+    		iPcsCache.Remove(i);
+    		iCacheCount--;   		
+    	}
+    }
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::IsLanguageSupportedL
+// Returns ETrue if this language is supported
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm1::IsLanguageSupportedL(TUint32 aLang)
+{
+    return iKeyMap->IsLanguageSupported(aLang);
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetUriForIdL
+// Get the URI string for this internal id
+// ----------------------------------------------------------------------------
+TDesC& CPcsAlgorithm1::GetUriForIdL(TUint8 aUriId)
+{
+    TBool found = EFalse;
+    TInt i = 0;
+    
+    for ( i = 0; i < iPcsCache.Count(); i++ )
+    {
+    	if ( iPcsCache[i]->GetUriId() == aUriId ) 
+    	{    	   
+    	   found = ETrue;
+    	   break;
+    	}
+    }	
+	
+	if ( ! found )
+	{
+		User::Leave(KErrNotFound);
+	}
+	
+	return *(iPcsCache[i]->GetUri()); 
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::FindStoreUri
+// Checks if this store exists
+// ----------------------------------------------------------------------------
+TInt CPcsAlgorithm1::FindStoreUri ( TDesC& aDataStore )
+{
+    for ( int i = 0; i < iPcsCache.Count(); i++ )
+    {
+    	if ( aDataStore.CompareC(*(iPcsCache[i]->GetUri())) == 0 ) 
+    	{
+    	   return i;   
+    	}
+    }
+
+    return -1;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::UpdateCachingStatus
+// Update caching status
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::UpdateCachingStatus(TDesC& aDataStore, TInt aStatus)
+{
+	PRINT ( _L("Enter CPcsAlgorithm1::UpdateCachingStatus") );
+	
+	TInt index = FindStoreUri(aDataStore);
+	iPcsCache[index]->UpdateCacheStatus(aStatus);
+	
+	// Check if any error occurred
+	// If so, update the cache status, Set the property and return
+	if( aStatus < 0)
+	{
+		SetCachingError(aDataStore, aStatus);
+		//return;
+	}
+	
+	// No error occurred
+	TCachingStatus status = ECachingComplete;
+	TBool atLeastOneStoreCachingCompleteWithErrors(EFalse);
+	for ( TInt i = 0; i < iPcsCache.Count(); i++ )
+	{
+		if( iPcsCache[i]->GetCacheStatus() == ECachingComplete)
+		  {
+	      continue;
+	      }	
+		else if ( iPcsCache[i]->GetCacheStatus() == ECachingCompleteWithErrors)
+		   {
+		 	 atLeastOneStoreCachingCompleteWithErrors = ETrue;
+		 	 continue;
+		   }
+		else
+		{
+			status = ECachingInProgress;
+			break;
+		}			
+	}
+	
+	if ( status == ECachingComplete )
+	{
+		// See if any error occurred while caching
+		// If so, change the status to ECachingCompleteWithErrors
+		if (( iCacheError != KErrNone ) || (atLeastOneStoreCachingCompleteWithErrors))
+			status = ECachingCompleteWithErrors;
+	}
+	
+	// Check if status changed
+	if ( status != iCacheStatus )
+	{
+		iCacheStatus = status;
+		RProperty::Set(KCStatus,0,iCacheStatus );
+	}
+	
+	PRINT ( _L("End CPcsAlgorithm1::UpdateCachingStatus") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::SetCachingError
+// Updates cachinge error
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::SetCachingError(TDesC& aDataStore, TInt aError)
+{
+	TBuf<KBufferMaxLen> store;
+	store.Copy(aDataStore);
+	PRINT2 ( _L("SetCachingError::URI %S ERROR %d"), &store, aError );
+
+	iCacheError = aError;
+	RProperty::Set(KCStatus,1,iCacheError );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetAllContentsL
+// Returns all the contents of a store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetAllContentsL ( const CPsSettings& aSettings,
+                                       RPointerArray<CPsData>& aResults )
+{
+	__LATENCY_MARK ( _L("CPcsAlgorithm1::GetAllContentsL") );
+    
+    PRINT ( _L("Enter CPcsAlgorithm1::GetAllContentsL") );   
+    
+    // Get the data stores
+    RPointerArray<TDesC> aDataStores;
+    aSettings.SearchUrisL(aDataStores);
+
+    // To hold array of results from different data stores
+    typedef RPointerArray<CPsData> CPSDATA_R_PTR_ARRAY;
+    RPointerArray<CPSDATA_R_PTR_ARRAY> iSearchResultsArr;
+    
+    // Get all contacts for each data store
+    for ( int dsIndex = 0; 
+          dsIndex < aDataStores.Count(); 
+          dsIndex++ )
+    {	        	
+        RPointerArray<CPsData> *temp = new (ELeave) RPointerArray<CPsData>();
+        iSearchResultsArr.Append(temp);
+        
+        TInt arrayIndex = GetCacheIndex(*(aDataStores[dsIndex]));
+        
+		if ( arrayIndex < 0 ) continue;
+		
+		CPcsCache* cache = GetCache(arrayIndex);
+        	      
+        cache->GetAllContentsL(*(iSearchResultsArr[dsIndex]));
+    }	   		   
+    	    	         	
+    aDataStores.ResetAndDestroy();    
+  
+    // Merge the results from different data stores
+    CPcsAlgorithm1Utils::FormCompleteSearchResultsL(iSearchResultsArr,
+    												aResults);
+  
+    // Cleanup the local arrays
+    for(TInt i = 0; i < iSearchResultsArr.Count(); i++)
+    {
+    	iSearchResultsArr[i]->Reset();
+    	delete iSearchResultsArr[i];
+    	iSearchResultsArr[i] = NULL;
+    }    
+    
+    iSearchResultsArr.Reset();    
+
+    PRINT1 ( _L("Number of results = %d"), aResults.Count() );
+   
+    PRINT ( _L("End CPcsAlgorithm1::GetAllContentsL") );
+    
+    __LATENCY_MARKEND ( _L("CPcsAlgorithm1::GetAllContentsL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::IsGroupSearchL
+// Checks if a group search is required
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm1::IsGroupSearchL ( CPsSettings& aSettings,
+                                       RArray<TInt>& aGroupIdArray )
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::IsGroupSearchL") );   
+    
+    // Get the groupIds in the seach settings
+    aSettings.GetGroupIdsL(aGroupIdArray);
+     
+    // Get the current URIs defined in settings    
+    RPointerArray<TDesC> searchUris;
+    aSettings.SearchUrisL(searchUris);
+    
+    if ( aGroupIdArray.Count() && (searchUris.Count() > aGroupIdArray.Count() ) )
+    {
+    	// There is an error, either there are more than one groups
+    	// or the settings contain a combination of group/non-group Uris
+    	searchUris.ResetAndDestroy();
+    	aGroupIdArray.Close();
+    	User::Leave(KErrArgument); 
+    }
+    
+    searchUris.ResetAndDestroy();
+        
+    PRINT ( _L("End CPcsAlgorithm1::IsGroupSearchL") );    
+    
+    if ( aGroupIdArray.Count() == 1 )
+        return ETrue;
+    
+    return EFalse;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ReplaceGroupsUriL
+// Replace groups uri to contacts uri
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::ReplaceGroupsUriL ( CPsSettings& aSettings )
+{
+	RPointerArray<TDesC> uri; 
+    
+    // Set contacts db uri
+	HBufC* cntdb = HBufC::NewL(KBufferMaxLen);
+	cntdb->Des().Copy(KVPbkDefaultCntDbURI);
+	uri.Append(cntdb);
+	aSettings.SetSearchUrisL(uri);
+	
+	// Cleanup
+	uri.ResetAndDestroy();
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::FilterSearchResultsForGroupsL
+// Filters the results that belong to a group
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::FilterSearchResultsForGroupsL(RArray<TInt>& contactsInGroup, 
+                                                   RPointerArray<CPsData>& aSearchResults)
+{
+	PRINT ( _L("Enter CPcsAlgorithm1::FilterSearchResultsForGroupsL") );   
+   
+	// for each search result
+	// Note: aSearchResults.Count() is to be checked everytime,
+	//       since the elements are being removed dynamically.
+	for ( TInt j = 0 ; j < aSearchResults.Count(); j++ )
+	{
+		TBool includeResult = EFalse;
+
+		if ( contactsInGroup.Find(aSearchResults[j]->Id()) != KErrNotFound )
+		{
+			includeResult = ETrue;
+		}
+
+		if ( includeResult == EFalse )
+		{
+			aSearchResults.Remove(j);
+			j--; // j is decremented, since that object is removed
+		}
+	}
+	        
+	PRINT ( _L("End CPcsAlgorithm1::FilterSearchResultsForGroupsL") );    
+}
+
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetContactsInGroupL
+// Recover contacts that belong to a group
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetContactsInGroupL ( TInt aGroupId, 
+                                           RArray<TInt>& aGroupContactIds )
+{	    
+    // Clear results array
+    aGroupContactIds.Reset();
+    
+    // Groups URI
+    HBufC* groupURI = HBufC::NewL(50);
+    groupURI->Des().Copy(KVPbkDefaultGrpDbURI);
+       
+    // Cache Index   
+    TInt cacheIndex = GetCacheIndex(*groupURI);
+    
+    // Cleanup
+    delete groupURI;
+    groupURI = NULL;
+    
+    // Get the groups contact ids 
+	if ( cacheIndex != -1 )
+	{
+		RPointerArray<CPsData> groups;
+		
+		// Get all groups
+		iPcsCache[cacheIndex]->GetAllContentsL(groups);
+	
+	    // Get all contacts in group
+		for ( TInt i = 0; i < groups.Count(); i++ )
+		{
+			if ( groups[i]->Id() == aGroupId )
+			{
+				groups[i]->IntDataExt(aGroupContactIds); // All contacts in group
+				break;
+			}		
+		}
+		
+		groups.Reset();	
+	}
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetDataOrderL
+// 
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetDataOrderL ( TDesC& aURI,
+                                     RArray<TInt>& aDataOrder )
+{
+    PRINT ( _L("End CPcsAlgorithm1::GetDataOrderL") );
+
+    TInt arrayIndex = -1;     
+    
+    if ( CPcsAlgorithm1Utils::IsGroupUri(aURI) )
+    {
+        // If search in a group uri, use contacts db
+        TBuf<255> cntdb(KVPbkDefaultCntDbURI);
+        arrayIndex = GetCacheIndex(cntdb);
+    }
+    else 
+    {		
+		arrayIndex = GetCacheIndex(aURI);
+    }
+    
+    if ( arrayIndex < 0 ) return;
+        
+    CPcsCache* cache = iPcsCache[arrayIndex];
+    
+    aDataOrder.Reset();
+    
+    // Get the data fields for this cache
+    cache->GetDataFields(aDataOrder);
+    
+    PRINT ( _L("End CPcsAlgorithm1::GetDataOrderL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetSortOrderL
+// 
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetSortOrderL ( TDesC& aURI,
+                                     RArray<TInt>& aDataOrder )
+{
+    PRINT ( _L("End CPcsAlgorithm1::GetSortOrderL") );
+
+    TInt arrayIndex = -1;     
+    
+    if ( CPcsAlgorithm1Utils::IsGroupUri(aURI) )
+    {
+        // If search in a group uri, use contacts db
+        TBuf<255> cntdb(KVPbkDefaultCntDbURI);
+        arrayIndex = GetCacheIndex(cntdb);
+    }
+    else 
+    {		
+		arrayIndex = GetCacheIndex(aURI);
+    }
+    
+    if ( arrayIndex < 0 ) return;
+    
+    CPcsCache* cache = iPcsCache[arrayIndex];
+    
+    aDataOrder.Reset();
+    
+    // Get the data fields for this cache
+    cache->GetSortOrder(aDataOrder);
+    
+    PRINT ( _L("End CPcsAlgorithm1::GetSortOrderL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ChangeSortOrderL
+// 
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::ChangeSortOrderL ( TDesC& aURI,
+                                        RArray<TInt>& aSortOrder )
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::ChangeSortOrderL.") );
+    
+    PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Sort order change received.") );
+    PRINT1 ( _L("URI = %S"), &aURI );
+    
+    // If URI is search in a group URI return       
+    if ( CPcsAlgorithm1Utils::IsGroupUri(aURI) )
+    {
+       PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Sort order change not supported.") );
+       return;	
+    }
+    
+    // Check if a cache exists
+    TInt arrayIndex = GetCacheIndex(aURI);
+    if ( arrayIndex < 0 )
+    {
+        PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Cache for URI doesn't exist.") );
+    	return;
+    }
+    
+    // Cache instance for this URI
+    CPcsCache* cache = iPcsCache[arrayIndex];
+        
+    // Check if received sort order is same as before
+    RArray<TInt> mySortOrder;
+    cache->GetSortOrder(mySortOrder);
+    
+    if ( aSortOrder.Count() == mySortOrder.Count() )    
+    {
+         TBool same = ETrue;
+         for ( int i = 0; i < mySortOrder.Count(); i++ )	
+         {
+            if ( mySortOrder[i] != aSortOrder[i] )
+     		{
+     			same = EFalse;
+     			break;
+     		}
+         }
+         
+         if ( same )
+         {
+             PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Same sort order received. Ignoring ...") );
+             PRINT ( _L("End CPcsAlgorithm1::ChangeSortOrderL.") );
+             mySortOrder.Reset();
+             return;
+         }
+    }
+    
+    mySortOrder.Reset();
+    
+    PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. New sort order received. Refreshing ...") );
+	// Set the new sort order on the cache
+	cache->SetSortOrder(aSortOrder);
+	
+    // Persist the changes in sort order
+    WriteSortOrderToCenRepL(aURI, aSortOrder);
+	
+	// Resort data
+	TInt err = KErrNone; 
+	TRAP(err, cache->ResortdataInPoolsL());
+	if ( err != KErrNone )
+	{
+		PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL() Set Caching Error ") ); 
+		SetCachingError(aURI, err);
+		UpdateCachingStatus(aURI,ECachingCompleteWithErrors);
+		return;
+	}	
+	
+	PRINT ( _L("End CPcsAlgorithm1::ChangeSortOrderL.") );
+}
+
+// ---------------------------------------------------------------------------------
+// Read the persisted sort order from the central repository
+// Persisted sort order is of form URI Field1 Field2 Field3 .. FieldN (space delimited)
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm1::ReadSortOrderFromCenRepL(TDesC& aURI, 
+                                              RArray<TInt>& aSortOrder)
+{
+    PRINT ( _L("Enter CPcsAlgorithm1::ReadSortOrderFromCenRepL.") );
+
+    aSortOrder.Reset();
+    
+	CRepository *repository = CRepository::NewL( KCRUidPSSortOrder );
+
+    // Read the sort order from cenrep
+    TBuf<KCRMaxLen> str;
+    
+    for ( TInt i(KCenrepFieldsStartKey); 
+          i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount; 
+          i++ )
+    {
+	    TInt err = repository->Get( i, str );
+	    
+	    if ( KErrNone != err )
+	    {
+		    break;
+	    }
+	    
+	    if (str != KNullDesC)
+	    {		    
+		    TLex lex(str);
+		    
+		    // Extract the URI
+		    TPtrC token = lex.NextToken();
+		    
+		    if ( aURI.Compare(token) == 0 )
+		    {
+		        // Extract the sort order
+		        token.Set(lex.NextToken());
+		        
+				while ( token.Length() != 0 )				
+				{	
+				    TLex lex1(token);
+				    
+				    TInt intVal;				    
+				    TInt err = lex1.Val(intVal);
+				    
+					if ( KErrNone == err )
+					{
+						aSortOrder.Append(intVal);
+					}				    	        		    				    
+				    
+					// Next token
+					token.Set(lex.NextToken());				
+				}	
+				
+				break;
+		    }		    		    
+	    }
+	    		
+    }
+    
+    delete repository;
+    
+    PRINT ( _L("End CPcsAlgorithm1::ReadSortOrderFromCenRepL.") );
+}
+
+// ---------------------------------------------------------------------------------
+// Write the sort order into the central repository
+// Persisted sort order is of form URI Field1 Field2 Field3 .. FieldN (space delimited)
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm1::WriteSortOrderToCenRepL(TDesC& aURI, 
+                                             RArray<TInt>& aSortOrder)
+{   
+    PRINT ( _L("Enter CPcsAlgorithm1::WriteSortOrderToCenRepL.") );
+
+    CRepository *repository = CRepository::NewL( KCRUidPSSortOrder );
+
+	// Check if there an entry for this URI in cenrep
+	TBuf<KCRMaxLen> str;
+	TInt keyIndex = -1;
+
+	for ( TInt i(KCenrepFieldsStartKey); 
+	  		   i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount; 
+	           i++ )
+	{
+		TInt err = repository->Get( i, str );
+
+		if ( KErrNone != err )
+		{
+		    PRINT ( _L("CPcsAlgorithm1::WriteSortOrderToCenRepL. cenrep error.") );
+		    return;
+		}
+
+		if (str != KNullDesC)
+		{		    
+		    TLex lex(str);
+		    
+		    // Extract the URI
+		    TPtrC token = lex.NextToken();
+		    
+		    if ( aURI.Compare(token) == 0 )
+		    {
+		         keyIndex = i; // i has the key index for this URI
+		         break;
+		    }
+		}
+	}
+	
+	// No entry for this URI in cenrep
+	// Find the next free location in cenrep
+	if ( keyIndex == -1 )
+	{
+		// Find the next free key index
+		for ( TInt i(KCenrepFieldsStartKey); 
+		  		   i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount; 
+		           i++ )
+	    {
+		    TInt err = repository->Get( i, str );
+
+			if ( KErrNone != err )
+			{
+			    PRINT ( _L("CPcsAlgorithm1::WriteSortOrderToCenRepL. cenrep error.") );
+			    return;
+			}
+
+			if (str == KNullDesC)
+			{
+			    keyIndex = i; // i has the next free location
+			    break;
+			}
+	    }
+	}
+	
+	if ( keyIndex == -1 )
+	{
+		PRINT ( _L("CPcsAlgorithm1::WriteSortOrderToCenRepL. Persist limit violated.") );
+		return;
+	}
+
+    // Persist the sort order
+	HBufC* str1 = HBufC::NewL(KCRMaxLen);
+	TPtr ptr(str1->Des());
+
+	// Append the URI
+	ptr.Append(aURI);
+	ptr.Append(KSpace);
+
+	// Append the sort order fields
+	for ( int j = 0; j < aSortOrder.Count(); j++ )
+	{
+		ptr.AppendNum(aSortOrder[j]);
+	    ptr.Append(KSpace);
+	}
+
+	// Write to persistent store
+	TInt err = repository->Set(keyIndex, ptr); 
+
+	User::LeaveIfError(err);
+
+	delete str1;   	
+  
+    delete repository;
+     
+    PRINT ( _L("End CPcsAlgorithm1::WriteSortOrderToCenRepL.") );
+}
+
+// ---------------------------------------------------------------------------------
+// WriteClientDataL.
+// Write the content required by client
+// ---------------------------------------------------------------------------------
+CPsClientData* CPcsAlgorithm1::WriteClientDataL( CPsData& aPsData )
+{
+    CPsClientData* clientData = CPsClientData::NewL();
+	CleanupStack::PushL(clientData);
+	
+	// set Id
+	clientData->SetId(aPsData.Id());
+	
+	// set Uri
+	clientData->SetUriL(GetUriForIdL(aPsData.UriId()));
+	
+	// set pointer to the each data element
+	for(TInt i = 0; i < aPsData.DataElementCount(); i++)
+	{
+		clientData->SetDataL(i, *(aPsData.Data(i)));
+	}
+	
+	// set data extension
+	clientData->SetDataExtensionL(aPsData.DataExtension());
+	    
+	// Set the Field match
+	clientData->SetFieldMatch(aPsData.DataMatch())  ;
+	CleanupStack::Pop(clientData);
+	
+	return clientData;
+}
+
+// ---------------------------------------------------------------------------------
+// DoLaunchPluginsL.
+// launch plugins by idle
+// ---------------------------------------------------------------------------------
+TInt CPcsAlgorithm1::DoLaunchPluginsL(TAny* aPtr)
+    {
+    CPcsAlgorithm1* ptr = (CPcsAlgorithm1*) aPtr;
+    ptr->DoLaunchPluginsL();
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------------
+// DoLaunchPluginsL.
+// lauch plugins
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm1::DoLaunchPluginsL()
+    {
+    // Initialize available data adapters
+    iPsDataPluginInterface = CPsDataPluginInterface::NewL(this, this);    
+    iPsDataPluginInterface->InstantiateAllPlugInsL();
+    
+    // Store the cache list in TLS
+    // Required to support sort order changes in a memory efficient way
+    // This avoids storing sort order information in the CPsData element
+    // and storing it in CPcsCache. Refer CPcsAlgorithm1Utils::CompareDataBySortOrderL
+    // to see how this is being used.
+    User::LeaveIfError( Dll::SetTls(&iPcsCache) );
+    
+    // Initialize cache
+    RPointerArray<TDesC> dataStores;    
+    
+    iPsDataPluginInterface->GetAllSupportedDataStoresL(dataStores);
+        
+    for ( int dIndex = 0; dIndex < dataStores.Count(); dIndex++ )
+    {
+    AddDataStore(*(dataStores[dIndex]));
+    }
+    dataStores.Reset();
+    }
+// End of file
+