pimappservices/calendar/server/src/agsextractor.cpp
changeset 0 f979ecb2b13e
child 83 5aadd1120515
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/server/src/agsextractor.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,562 @@
+// Copyright (c) 1997-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 "agsextractor.h"
+
+#include "agmsimpleentry.h"
+#include "agsentrymodel.h"
+#include "agmrptdef.h"
+#include "agmutil.h"
+#include "agssortinstance.h"
+#include "agsindex.h"
+#include "agssort.h"
+
+// This represents the number of instances that have been found by a next or previous instance
+// call that could, when sorted into order, appear before the search from instance
+TInt gPossibleInstancesOutsideRange(0);
+
+// ----------------------------CAgnInstanceExtractor------------------------
+CAgnInstanceExtractor::CAgnInstanceExtractor(TAgnIterator* aIterator, CAgnEntryModel& aEntryModel)
+	:iEntryModel(aEntryModel), iIterator(aIterator)
+	{
+	__ASSERT_ALWAYS(aIterator, Panic(EAgmErrNullPointer));
+	}
+
+CAgnInstanceExtractor::~CAgnInstanceExtractor()
+	{
+	delete iIterator;
+	}
+
+#ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS
+/** Determines whether to continue the Find Instances search.
+@param aAlarmedInstanceSearch Whether this is an alarmed instance search
+@param aSearchRangeEndLocal The local time of the end of the search range
+@internalComponent
+*/
+TBool CAgnInstanceExtractor::ContinueSearchL(const TBool aAlarmInstanceSearch, const TTime& aSearchRangeEndLocal) const
+	{
+	TBool ret(ETrue);
+	if (aAlarmInstanceSearch)
+		{
+		ret = !iIterator->AtEnd();
+		}
+	else
+		{
+		ret = !iIterator->AtEnd() 
+			&& ( (iIterator->CurrentElement().ValidFromTimeLocalL() == Time::NullTTime()) 
+					|| iIterator->CurrentElement().ValidFromTimeLocalL() <= aSearchRangeEndLocal);
+		}
+	return ret;
+	}
+
+/** Inserts an instance into an instance list.
+@param aAlarmInstanceSearch Whether this is an alarmed instance search
+@param aInstances The instance is inserted into this list
+@param aInstance The instance to insert
+@param aFindInstanceParams Defines the search range
+@internalComponent
+*/
+void CAgnInstanceExtractor::InsertInstanceL(const TBool aAlarmInstanceSearch, 
+											CArrayFix<TAgnSortInstance>& aInstances, 
+											TAgnSortInstance& aInstance,
+											const TFindInstanceParams& aFindInstanceParams) const
+	{
+	if (aAlarmInstanceSearch)
+		{	
+		 if (aInstance.CheckAlarmTimeWithinL(aFindInstanceParams))
+			 {
+			 TAgnAlarmSortKey sortKey;	// Only needed for function call below
+			 aInstances.InsertIsqAllowDuplicatesL(aInstance, sortKey);
+			 }
+		}
+	else
+		{
+		if (aInstance.CheckStartAndEndDateOverlap(aFindInstanceParams))
+			{
+			aInstances.AppendL(aInstance);
+			}
+		}
+	}
+#endif
+
+/** Finds all instances in a time range that match the filter requirements
+
+@param aInstances The instance list to append instances to
+@param aSearchParams The filter requirements for the instance search
+
+@internalComponent
+*/
+void CAgnInstanceExtractor::FindInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams)
+	{		  	
+	TTime searchRangeStartLocal(aSearchParams.iRangeStart.LocalL());
+	TTime searchRangeEndLocal(aSearchParams.iRangeEnd.LocalL());
+	
+	TTime startTime(searchRangeStartLocal);	
+	
+#ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS
+	TBool alarmInstanceSearch(EFalse);		
+	alarmInstanceSearch = aSearchParams.iFilter.IsAlarmedInstanceSearch();
+	if (alarmInstanceSearch)
+		{
+		iIterator->StartL();
+		}
+	else
+		{
+		TTime startTime(searchRangeStartLocal);
+		iIterator->GotoL(startTime);
+		}
+
+	TFindInstanceParams findInstanceParams(aSearchParams);
+	
+	for (; ContinueSearchL(alarmInstanceSearch, searchRangeEndLocal); iIterator->NextL())
+		{
+		const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement());
+		 
+		if (alarmInstanceSearch)
+			{
+			searchRangeStartLocal = aSearchParams.iRangeStart.LocalL() + KSimpleEntry.AlarmOffset();
+			searchRangeEndLocal = aSearchParams.iRangeEnd.LocalL() + KSimpleEntry.AlarmOffset();
+			findInstanceParams.iRangeStart.SetLocalL(searchRangeStartLocal);
+			findInstanceParams.iRangeEnd.SetLocalL(searchRangeEndLocal);
+			}
+				
+		if(iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams))
+   			{
+   			const CAgnRptDef* KRptDef(KSimpleEntry.RptDef());
+   			if (KRptDef)
+   				{	
+   				TTime instanceTime;   				
+   				if (Filter()->RptNextInstanceOnly())
+   					{
+   					// if this flag is set we only want the next instance after the start time
+ 					if (KRptDef->NudgeNextInstanceL(searchRangeStartLocal, instanceTime, ETrue) && instanceTime <= searchRangeEndLocal)
+   						 {
+	   					 TAgnSortInstance instance(KSimpleEntry);
+	   					 instance.SetL(instanceTime, UndatedTodoTime());
+	   					 InsertInstanceL(alarmInstanceSearch, aInstances, instance, findInstanceParams);
+	   					 }
+	   				}
+   				else
+   					{
+   					// nudge backwards from the end of the search range
+ 					TTime fromTime(AgnDateTime::ConvertToLocalTimeL(KSimpleEntry.DurationPlusL(AgnDateTime::ConvertToUtcTimeL(searchRangeEndLocal)) + TTimeIntervalMicroSeconds(1)));
+   					while (KRptDef->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime)
+ 							&& (KSimpleEntry.DurationPlusL(instanceTime) >= searchRangeStartLocal) )
+   						{
+   						TAgnSortInstance instance(KSimpleEntry);
+   						instance.SetL(instanceTime, UndatedTodoTime());
+   						InsertInstanceL(alarmInstanceSearch, aInstances, instance, findInstanceParams);
+   						fromTime = instanceTime;
+   						}
+   					}
+   				}
+   			else
+   				{
+   				// It is a non-repeating entry
+   			    TAgnSortInstance instance(KSimpleEntry);
+   			    instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime());
+   			    InsertInstanceL(alarmInstanceSearch, aInstances, instance, findInstanceParams);
+   				}
+   			}
+		}
+	
+#else	
+	for (iIterator->GotoL(startTime); !iIterator->AtEnd() && ( (iIterator->CurrentElement().ValidFromTimeLocalL() == Time::NullTTime()) || iIterator->CurrentElement().ValidFromTimeLocalL() <= searchRangeEndLocal) ; iIterator->NextL())
+		{
+		const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement());
+		if(iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams))
+   			{
+   			const CAgnRptDef* KRptDef(KSimpleEntry.RptDef());
+   			if (KRptDef)
+   				{	
+   				TTime instanceTime;   				
+   				if (Filter()->RptNextInstanceOnly())
+   					{
+   					// if this flag is set we only want the next instance after the start time
+ 					if (KRptDef->NudgeNextInstanceL(searchRangeStartLocal, instanceTime, ETrue) && instanceTime <= searchRangeEndLocal)
+   						 {
+   						 TAgnSortInstance instance(KSimpleEntry);
+   						 instance.SetL(instanceTime, UndatedTodoTime());
+   						 if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+   							{
+   						  	aInstances.AppendL(instance);
+   						  	}	
+   						 }
+   					}
+   				else
+   					{
+   					// nudge backwards from the end of the search range
+ 					TTime fromTime(AgnDateTime::ConvertToLocalTimeL(KSimpleEntry.DurationPlusL(AgnDateTime::ConvertToUtcTimeL(searchRangeEndLocal)) + TTimeIntervalMicroSeconds(1)));
+   					while (KRptDef->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime)
+ 							&& (KSimpleEntry.DurationPlusL(instanceTime) >= searchRangeStartLocal) )
+   						{
+   						TAgnSortInstance instance(KSimpleEntry);
+   						instance.SetL(instanceTime, UndatedTodoTime());
+   						if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+   							{
+   						  	aInstances.AppendL(instance);
+   						  	}	
+   						fromTime = instanceTime;
+   						}
+   					}
+   				}
+   			else
+   				{
+   				// It is a non-repeating entry
+   			    TAgnSortInstance instance(KSimpleEntry);
+   			    instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime());
+   			    if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+   			    	{
+   			 	   	aInstances.AppendL(instance);
+   			 	   	}	
+   				}
+   			}
+		}
+#endif
+	}	
+
+		
+// ----------------------------TAgnInstanceExtractor----------------------------
+
+/** Instance extractor for all entry types
+
+@internalComponent
+*/
+TAgnInstanceExtractor::TAgnInstanceExtractor(CAgnSimpleEntryTable& aEntryInfoTable)
+	:iSimpleEntryTable(&aEntryInfoTable)
+	{
+	}
+
+/** Instances are obtained from each index selected by the filter by mean of an extractor.
+
+The instances are returned in the order defined by TAgnDaySortKey
+
+@internalComponent
+*/ 
+void TAgnInstanceExtractor::FindInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams)
+    {
+
+	RArray<TInt> indexList;
+	CleanupClosePushL(indexList);
+
+	// Get the indexes of interest as per filter
+	//
+	iSimpleEntryTable->GetFilteredIndexListL(indexList, aSearchParams.iFilter);
+	
+   	// Extract instances from each index (both floating and fixed time modes).
+   	// Instances are extracted from each index of interest using a "extractor".
+   	// The extractor is initialized with the particular index when "GetExtractor" is called.
+   	//
+   	const TInt KIndexCount = indexList.Count();
+	for (TInt i = 0; i < KIndexCount; ++i)
+   		{
+		iSimpleEntryTable->GetExtractor(indexList[i], MAgnCalendarTimeMode::EFloating, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->FindInstancesL(aInstances, aSearchParams);
+		iSimpleEntryTable->GetExtractor(indexList[i], MAgnCalendarTimeMode::EFixedUtc, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->FindInstancesL(aInstances, aSearchParams);
+   		}
+
+	CleanupStack::PopAndDestroy(&indexList); // Close()
+	}
+
+void TAgnInstanceExtractor::NextPossibleInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams)
+	{
+	RArray<TInt> indexList;
+	CleanupClosePushL(indexList);
+	
+	// Get the indices of interest as per filter
+	iSimpleEntryTable->GetFilteredIndexListL(indexList, aSearchParams.iFilter);
+	
+	gPossibleInstancesOutsideRange = 0;
+
+	const TInt KIndexCount = indexList.Count();
+	for (TInt ii = 0; ii < KIndexCount; ++ii)
+		{
+		iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFloating, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->NextInstancesL(aInstances, aSearchParams);
+		iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFixedUtc, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->NextInstancesL(aInstances, aSearchParams);
+		}
+	CleanupStack::PopAndDestroy(&indexList); // Close()
+	}
+
+void TAgnInstanceExtractor::PreviousPossibleInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams)
+	{
+	RArray<TInt> indexList;
+	CleanupClosePushL(indexList);
+	
+	// Get the indices of interest as per filter
+	iSimpleEntryTable->GetFilteredIndexListL(indexList, aSearchParams.iFilter);
+	
+	gPossibleInstancesOutsideRange = 0;
+	
+   	const TInt KIndexCount = indexList.Count();
+	for (TInt ii = 0 ; ii < KIndexCount ; ++ii) 
+		{
+		iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFloating, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->PreviousInstancesL(aInstances, aSearchParams);
+		iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFixedUtc, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->PreviousInstancesL(aInstances, aSearchParams);
+		}
+	CleanupStack::PopAndDestroy(&indexList); // Close()
+	}
+void CAgnInstanceExtractor::NextInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams)
+	{
+	const TTime KSearchFromTimeLocal(aSearchParams.iInstance.iId.Date().IsSet() ? aSearchParams.iInstance.iId.Date().LocalL() : aSearchParams.iUndatedTodoTimeLocal);
+	const TTime KSearchRangeEndLocal(aSearchParams.iRangeEnd.LocalL());
+	
+	TTime searchFromTimeLocal(KSearchFromTimeLocal);
+	TTime lastMatchedTimeLocal(KSearchFromTimeLocal);
+	
+	TAgnDaySortKey sortKey(AgnDateTime::MaxDate(), UndatedTodoTime());
+	
+	// This time is used so that we do not add instances to the list that are after
+	// the Nth one that has been found because we know that we will not need them
+	TTime NthInstanceTimeLocal(AgnDateTime::MaxDate());
+
+	TInt numInstancesFound(0);
+
+	for (iIterator->GotoL(searchFromTimeLocal) ; !iIterator->AtEnd() && (iIterator->CurrentElement().ValidFromTimeLocalL() <= KSearchRangeEndLocal) && (iIterator->CurrentElement().ValidFromTimeLocalL() <= NthInstanceTimeLocal) ; iIterator->NextL())
+		{
+		if ( aInstances.Count() > (aSearchParams.iNumInstances + gPossibleInstancesOutsideRange) )
+			{
+			// We don't need instances after aSearchParams.iNumInstances
+			NthInstanceTimeLocal = aInstances.At(aSearchParams.iNumInstances + gPossibleInstancesOutsideRange).InstanceDate();
+			}
+
+		const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement());
+		
+		if (iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams))
+		    {
+		    // find out where this instance is in the list
+		        	    		    
+		    if (KSimpleEntry.RptDef())
+		    	{
+    			// nudge backwards to find instances that over lap into the start of the range
+    			// add a microsecond to the search from time so that we find instances that start exactly on the start range
+		    	TTime fromTime = AgnDateTime::ConvertToLocalTimeL(AgnDateTime::ConvertToUtcTimeL(KSearchFromTimeLocal) + TTimeIntervalMicroSeconds(1));
+    			TTime instanceTime;
+    			
+    			while (KSimpleEntry.RptDef()->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime))
+    				{
+    				TAgnSortInstance instance(KSimpleEntry);
+    				instance.SetL(instanceTime, UndatedTodoTime());
+    				
+    	    		if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+    	    			{
+    	    			aInstances.InsertIsqAllowDuplicatesL(instance, sortKey);
+    	    			
+    	    			// it is possible that this instance appears before
+		    			// the starting instance when sorted into order
+    	    			++gPossibleInstancesOutsideRange;
+    	    			
+    	    			if (!aSearchParams.iInstance.iId.IsNullId())
+	    			    	{
+	    			    	// We are searching from a particular instance
+	    			    	// so one nudge backwards is good enough to get the search from instance
+	    			    	break;
+	    			    	}
+    	    			}
+    	    		else
+    	    			{
+    	    			// There are no more instances in the repeat that overlap into the start of the search range
+    	    			break;
+    	    			}
+    	    		
+    				fromTime = instanceTime;
+    				}
+    			
+    			// Try to get the next n number of instances from the repeat rule
+    			numInstancesFound = 0;
+    			fromTime = KSearchFromTimeLocal;
+    			while ( KSimpleEntry.RptDef()->NudgeNextInstanceL(fromTime, instanceTime, ETrue)
+    					&& aSearchParams.iNumInstances >= ++numInstancesFound
+    					&& KSimpleEntry.DurationMinusL(instanceTime) <= KSearchRangeEndLocal
+    					&& KSimpleEntry.DurationMinusL(instanceTime) <= NthInstanceTimeLocal )
+    				{
+    				TAgnSortInstance instance(KSimpleEntry);
+    				instance.SetL(instanceTime, UndatedTodoTime());
+    				
+    	    		if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+    	    			{
+    	    			aInstances.InsertIsqAllowDuplicatesL(instance, sortKey);
+    	    			}
+    	    		
+    				fromTime = instanceTime;
+    				}
+		    	}
+		    else
+		    	{
+		    	// It is a non-repeating entry
+		    	
+				TAgnSortInstance instance(KSimpleEntry);
+				instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime());
+				
+			    if ( lastMatchedTimeLocal > KSearchFromTimeLocal )
+					{
+					// We now have any instances that are the same as the search from time
+					
+					if (++numInstancesFound > aSearchParams.iNumInstances)
+						{
+						// We now have the number of requested instances
+						
+						if (iIterator->CurrentKey() > lastMatchedTimeLocal)
+							{
+							// Break when all the instances that are at
+							// the same time as the last instance have been found  
+							break;
+							}
+						}
+					}
+			    
+				// Add the instance to the list
+			    if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+			    	{
+	    			aInstances.InsertIsqAllowDuplicatesL(instance, sortKey);
+	    			lastMatchedTimeLocal = instance.InstanceDate();
+	    			
+	    			if (lastMatchedTimeLocal == KSearchFromTimeLocal)
+		    			{
+		    			// it is possible that this instance appears before
+		    			// the starting instance when sorted into order
+		    			++gPossibleInstancesOutsideRange;
+		    			}
+			    	}
+		    	}
+		    }
+		}
+	}
+
+/** Finds the previous n number of instance that match the filter requirements
+
+The filter includes the time to search from and the search time range.
+
+@param aInstances The instance list to append instances to
+@param aSearchParams The filter requirements for the instance search.  This includes how many instances to find.
+
+@internalComponent
+*/
+void CAgnInstanceExtractor::PreviousInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams)
+	{
+	const TTime KSearchFromTimeLocal(aSearchParams.iInstance.iId.Date().IsSet() ? aSearchParams.iInstance.iId.Date().LocalL() : aSearchParams.iUndatedTodoTimeLocal);
+	const TTime KSearchRangeStartLocal(aSearchParams.iRangeStart.LocalL());
+	
+	TTime searchFromTime(KSearchFromTimeLocal);
+	TTime lastMatchedTime(KSearchFromTimeLocal);
+	
+	TAgnDaySortKey sortKey(AgnDateTime::MaxDate(), UndatedTodoTime());
+	
+	// This time is used so that we do not add instances to the list that are after
+	// the Nth one that has been found because we know that we will not need them
+	TTime NthInstanceTime(AgnDateTime::MinDate());
+	
+	TInt numInstancesFound(0);
+	
+	for (iIterator->GotoLessOrEqualL(searchFromTime) ; !iIterator->AtStart() ; iIterator->PreviousL())
+		{
+		if ( aInstances.Count() > (aSearchParams.iNumInstances + gPossibleInstancesOutsideRange) )
+			{
+			// We don't need instances after aSearchParams.iNumInstances
+			NthInstanceTime = aInstances.At( aInstances.Count() - 1 - (aSearchParams.iNumInstances + gPossibleInstancesOutsideRange) ).InstanceDate();
+			}
+
+		const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement());
+		
+		if(iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams))
+		    {
+		    if (KSimpleEntry.RptDef())
+		    	{
+				// find instances that overlap into the end of the range
+				TTime fromTime = AgnDateTime::ConvertToLocalTimeL(AgnDateTime::ConvertToUtcTimeL(KSearchFromTimeLocal) - TTimeIntervalMicroSeconds(1));
+				TTime instanceTime;
+				
+				while (KSimpleEntry.RptDef()->NudgeNextInstanceL(fromTime, instanceTime, ETrue))
+					{
+					// get instances that are the same as the start time
+					TAgnSortInstance instance(KSimpleEntry);
+					instance.SetL(instanceTime, UndatedTodoTime());
+					if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+		    			{
+		    			aInstances.InsertIsqAllowDuplicatesL(instance, sortKey);
+		    			
+		    			++gPossibleInstancesOutsideRange;
+		    			
+    	    			if (!aSearchParams.iInstance.iId.IsNullId())
+    			    		{
+    			    		// We are searching from a particular instance
+    			    		// so one nudge forwards is good enough to get the search from instance
+    			    		break;
+    			    		}
+		    			}
+					else
+						{
+						break;
+						}
+					
+					fromTime = instanceTime;
+					}
+				
+				// find n number of instances in the past
+				numInstancesFound = 0;
+				fromTime = KSearchFromTimeLocal;
+					
+				while (KSimpleEntry.RptDef()->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime)
+						&& ++numInstancesFound <= aSearchParams.iNumInstances
+						&&  iIterator->CurrentElement().DurationPlusL(instanceTime) >= KSearchRangeStartLocal
+						&&  iIterator->CurrentElement().DurationPlusL(instanceTime) >= NthInstanceTime)
+					{
+					// get previous n number of instances before the start time
+					TAgnSortInstance instance(KSimpleEntry);
+					instance.SetL(instanceTime, UndatedTodoTime());
+					
+					if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+		    			{
+		    			aInstances.InsertIsqAllowDuplicatesL(instance, sortKey);
+		    			}
+								
+					fromTime = instanceTime;
+					}
+			    }
+		    else
+		    	{
+		    	// This is a non-repeating entry
+
+	    		TAgnSortInstance instance(KSimpleEntry);
+	    		instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime());	
+	    		
+	    		if (lastMatchedTime > KSearchFromTimeLocal)
+	    			{
+	    			// We now have all instances that are the same as the end time
+	    			if (++numInstancesFound > aSearchParams.iNumInstances)
+	    				{
+	    				if (lastMatchedTime > instance.InstanceDate())
+	    					{
+	    					// We now have all instances that are the same as
+	    					// the nth instances before the end time
+	    					break;
+	    					}
+	    				}
+	    			}
+	    			
+	    		// Add the instance to the list
+	    		if (instance.CheckStartAndEndDateOverlap(aSearchParams))
+	    			{
+	    			aInstances.InsertIsqAllowDuplicatesL(instance, sortKey);
+	    			lastMatchedTime = instance.InstanceDate();
+	    			
+	    			if (lastMatchedTime == KSearchFromTimeLocal)
+	    				{
+	    				++gPossibleInstancesOutsideRange;
+	    				}
+	    			}
+	    		}
+		    }
+		}
+	}
+