pimappservices/calendar/server/src/agstzruleindex.cpp
changeset 0 f979ecb2b13e
child 18 d68a4b5d5885
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/server/src/agstzruleindex.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,927 @@
+// Copyright (c) 2008-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 <vtzrules.h>
+#include <tz.h>
+#include "agmentry.h"
+#include "agmtlsproxy.h"
+#include "agmtzrules.h"
+#include "agstzruleindex.h"
+#include "agmpanic.h"
+#include "agmrptdef.h"
+#include "agsfilemanager.h"
+
+const TUid KUidAgnSystemTzIndex = {0x10285b96};
+const TUid KUidAgnImportedTzIndex = {0x10285b97};
+const TUid KUidAgnTimeStamp = {0x102863fb};
+
+const TInt KMinYear = 0;
+const TInt KMaxYear = 9999;
+
+/* ------------------- CAgnTzRuleIndexItem -------------------*/
+CAgnTzRuleIndexItem::CAgnTzRuleIndexItem(TStreamId aStreamId, CTzRules* aRule) :
+	iRefCount(1), iTzRules(aRule)
+	{
+	iStreamId = aStreamId;
+	}
+
+CAgnTzRuleIndexItem::CAgnTzRuleIndexItem() :
+	iRefCount(1), iTzRules(NULL)
+	{
+	}
+
+CAgnTzRuleIndexItem* CAgnTzRuleIndexItem::NewL(RReadStream& aStream)
+	{
+	CAgnTzRuleIndexItem* self = new (ELeave) CAgnTzRuleIndexItem();
+	CleanupStack::PushL(self);
+	self->InternalizeL(aStream);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CAgnTzRuleIndexItem* CAgnTzRuleIndexItem::NewL(TStreamId aStreamId, CTzRules* aTzRule)
+	{
+	CAgnTzRuleIndexItem* self = new (ELeave) CAgnTzRuleIndexItem(aStreamId, aTzRule);
+	return self;
+	}
+
+CAgnTzRuleIndexItem::~CAgnTzRuleIndexItem()
+	{
+	delete iTzRules;
+	}
+
+void CAgnTzRuleIndexItem::IncrementRef()
+	{
+	++iRefCount;
+	}
+
+TInt CAgnTzRuleIndexItem::DecrementRef()
+	{
+	__ASSERT_DEBUG(iRefCount>0, User::Invariant());
+	return --iRefCount;
+	}
+
+void CAgnTzRuleIndexItem::ExternalizeL(RWriteStream& aStream) const
+	{
+	aStream.WriteInt16L(iRefCount);
+	aStream << iStreamId;
+	}
+
+void CAgnTzRuleIndexItem::InternalizeL(RReadStream& aStream)
+	{
+	iRefCount = aStream.ReadInt16L();
+	aStream >> iStreamId;
+	}
+
+void CAgnTzRuleIndexItem::SetRule(CTzRules* aTzRules)
+	{
+	if (iTzRules)
+		{
+		delete iTzRules;
+		}
+	iTzRules = aTzRules;
+	}
+
+CTzRules* CAgnTzRuleIndexItem::TzRule() const
+	{
+	return iTzRules;
+	}
+
+const TStreamId& CAgnTzRuleIndexItem::StreamId() const
+	{
+	return iStreamId;
+	}
+
+TBool CAgnTzRuleIndexItem::IsSystemTzRule() const
+	{
+	return EFalse;
+	}
+
+/* ------------------- CAgnSystemTzRuleIndexItem -------------------*/
+void CAgnSystemTzRuleIndexItem::ConstructL(const TDesC8& aTzId)
+	{
+	iTzId = aTzId.AllocL();
+	}
+
+CAgnSystemTzRuleIndexItem* CAgnSystemTzRuleIndexItem::NewL(TStreamId aStreamId,	const TDesC8& aTzId, CTzRules* aRule)
+	{
+	CAgnSystemTzRuleIndexItem* self = new (ELeave) CAgnSystemTzRuleIndexItem(aStreamId, aRule);
+	CleanupStack::PushL(self);
+	self->ConstructL(aTzId);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CAgnSystemTzRuleIndexItem::CAgnSystemTzRuleIndexItem() :
+	CAgnTzRuleIndexItem(), iTzId(NULL)
+	{
+	}
+
+CAgnSystemTzRuleIndexItem::CAgnSystemTzRuleIndexItem(TStreamId aStreamId,
+		CTzRules* aRules) :
+	CAgnTzRuleIndexItem(aStreamId, aRules), iTzId(NULL)
+	{
+	}
+
+CAgnSystemTzRuleIndexItem::~CAgnSystemTzRuleIndexItem()
+	{
+	delete iTzId;
+	}
+
+CAgnSystemTzRuleIndexItem* CAgnSystemTzRuleIndexItem::NewL(RReadStream& aStream)
+	{
+	CAgnSystemTzRuleIndexItem* self = new (ELeave) CAgnSystemTzRuleIndexItem();
+	CleanupStack::PushL(self);
+	self->InternalizeL(aStream);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+const TDesC8& CAgnSystemTzRuleIndexItem::TzId() const
+	{
+	return *iTzId;
+	}
+
+void CAgnSystemTzRuleIndexItem::ExternalizeL(RWriteStream& aStream) const
+	{
+	CAgnTzRuleIndexItem::ExternalizeL(aStream);
+	aStream << *iTzId;
+	}
+
+void CAgnSystemTzRuleIndexItem::InternalizeL(RReadStream& aStream)
+	{
+	CAgnTzRuleIndexItem::InternalizeL(aStream);
+	iTzId = HBufC8::NewL(aStream, KMaxTInt);
+	}
+
+TBool CAgnSystemTzRuleIndexItem::IsSystemTzRule() const
+	{
+	return ETrue;
+	}
+
+/* ------------------- CAgnTzRuleIndex -------------------*/
+CAgnTzRuleIndex::CAgnTzRuleIndex(CStreamDictionary& aDictionary, CFileStore& aStore) :
+	iDictionary(&aDictionary),
+	iStore(&aStore),
+	iPosCurSystemTzRule(KErrNotFound),
+	iPosFetchedLastTime(0),
+	iTzDbChangeTimeStamp(Time::NullTTime()),
+	iTzRulesLastModifiedTime(Time::NullTTime())
+	{
+	}
+
+CAgnTzRuleIndex* CAgnTzRuleIndex::NewL(CStreamDictionary& aDictionary, CFileStore& aStore)
+	{
+	CAgnTzRuleIndex* self = new(ELeave) CAgnTzRuleIndex(aDictionary, aStore);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return (self);
+	}
+
+void CAgnTzRuleIndex::ConstructL()
+	{
+	iTimeZoneAccessor = CAgnTlsProxy::CreateL(CAgnTlsProxy::TAgnTlsTzRulesType_Server);
+
+	iSystemRuleStreamId = ReadItemsFromStoreL(KUidAgnSystemTzIndex);
+	iUserDefinedRuleStreamId = ReadItemsFromStoreL(KUidAgnImportedTzIndex);
+
+	RTz& tzServer = iTimeZoneAccessor->TzServer();
+	CTzId* tzid = tzServer.GetTimeZoneIdL();
+	CleanupStack::PushL(tzid);
+	HandleCurrentTimeZoneChangeL(*tzid);
+	CleanupStack::PopAndDestroy(tzid);
+	}
+
+/* Read the time stamp of time zone database has been modified last time.
+
+- If the file is newly created, the time stamp will be set to current time
+- If the file is re-opened, read the time stamp from the file.
+- If the file is re-opened, but there isn't a time stamp, the time stamp will be set to current time
+ */
+void CAgnTzRuleIndex::ReadTimeStampL()
+	{
+	TStreamId streamId = iDictionary->At(KUidAgnTimeStamp);
+
+	if (streamId == KNullStreamId)
+		{//There is not a time stamp in the file either it is newly created or an existing one.
+		TTime currentTime;
+		currentTime.UniversalTime();
+		iTzDbChangeTimeStamp = currentTime;
+
+		if (RefreshTzRulesL())
+			{
+			iTzRulesLastModifiedTime = currentTime;
+			}
+		PersistToStoreL(KUidAgnTimeStamp);
+		}
+	else
+		{//iTzChangTimeStamp is read from file
+		ReadFromStoreL(KUidAgnTimeStamp, EFalse);
+		}
+	}
+
+/** Check if the time zone server has been modified since last time the
+ * Calendar server shut down. If so, the time zones of entries cached in the Calendar
+ * will be updated. Calendar clients will be also notified with the change if
+ * any of time zones associated with Calendar entries have been modified.
+ *
+ * This function is called when a Calendar file is opened.
+ *
+ */
+void CAgnTzRuleIndex::CheckTzDbModificationL(CAgnServFile& aAgnServFile)
+	{
+	iAgnFile = &aAgnServFile;
+	ReadTimeStampL();
+	//This will result in HandleTzRulesChangeL to be called immediatly if a tz change has been published.
+	iTimeZoneAccessor->AddSystemTimeObserverL(this);
+	}
+/*
+ Called when the file is closed. It will write the current time to the Calendar file.
+ */
+void CAgnTzRuleIndex::WriteTimeStampL()
+	{
+	TStreamId streamId = iDictionary->At(KUidAgnTimeStamp);
+	RStoreWriteStream writeStream;
+	writeStream.ReplaceLC(*iStore, streamId);
+	ExternalizeTimesL(writeStream);
+	writeStream.CommitL();
+	CleanupStack::PopAndDestroy(&writeStream);
+	iStore->CommitL();
+
+	}
+void CAgnTzRuleIndex::ExternalizeTimesL(RStoreWriteStream& aWriteStream) const
+	{
+	aWriteStream << I64LOW(iTzDbChangeTimeStamp.Int64());
+	aWriteStream << I64HIGH(iTzDbChangeTimeStamp.Int64());
+	aWriteStream << I64LOW(iTzRulesLastModifiedTime.Int64());
+	aWriteStream << I64HIGH(iTzRulesLastModifiedTime.Int64());
+	}
+
+void CAgnTzRuleIndex::InternalizeTimesL(RReadStream& aReadStream)
+	{
+	TUint32 low = aReadStream.ReadUint32L();
+	TUint32 high = aReadStream.ReadUint32L();
+	iTzDbChangeTimeStamp = TTime(MAKE_TINT64(high, low));
+
+	low = aReadStream.ReadUint32L();
+	high = aReadStream.ReadUint32L();
+	iTzRulesLastModifiedTime = TTime(MAKE_TINT64(high, low));
+	}
+
+/* Externalise an array of tz rules or a time stamp to first time Calendar file.
+
+ @param aUid refer to uid of object to write to the file.
+ @return Stream Id refer to the object being written to the file
+ */
+TStreamId CAgnTzRuleIndex::PersistToStoreL(const TUid& aUid)
+	{
+	RStoreWriteStream writeStream;
+	TStreamId streamId = writeStream.CreateLC(*iStore);
+	if (aUid == KUidAgnSystemTzIndex)
+		{
+		ExternalizeRulesL(writeStream, iSystemTzRules);
+		}
+	else
+		if (aUid == KUidAgnImportedTzIndex)
+			{
+			ExternalizeRulesL(writeStream, iUserDefinedTzRules);
+			}
+		else
+			{
+			__ASSERT_ALWAYS(aUid == KUidAgnTimeStamp,User::Invariant());
+			ExternalizeTimesL(writeStream);
+			}
+
+	writeStream.CommitL();
+	CleanupStack::PopAndDestroy(&writeStream);
+
+	iDictionary->AssignL(aUid, streamId);
+
+	// Re-write the dictionary stream
+	RStoreWriteStream stream;
+	TStreamId rootStreamId = iStore->Root();
+	stream.ReplaceLC(*iStore, rootStreamId);
+	stream<< *iDictionary;
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(); // dictionary stream
+	iStore->CommitL();
+	return streamId;
+	}
+
+void CAgnTzRuleIndex::ReadFromStoreL(const TUid& aUid, TBool aRollback)
+	{
+	TStreamId streamId = iDictionary->At(aUid);
+	__ASSERT_ALWAYS(streamId != KNullStreamId, User::Leave(KErrNotFound));
+	RStoreReadStream readStream;
+	readStream.OpenLC(*iStore, streamId);
+	if (aUid == KUidAgnSystemTzIndex)
+		{
+		InternalizeRulesL(readStream, ETrue, aRollback);
+		}
+	else
+		if (aUid == KUidAgnImportedTzIndex)
+			{
+			InternalizeRulesL(readStream, EFalse, aRollback);
+			}
+		else
+			{
+			__ASSERT_ALWAYS(aUid==KUidAgnTimeStamp,User::Invariant());
+			InternalizeTimesL(readStream);
+			}
+
+	CleanupStack::PopAndDestroy(&readStream);
+	}
+
+TStreamId CAgnTzRuleIndex::ReadItemsFromStoreL(const TUid& aUid, TBool aRollback)
+	{
+	TStreamId streamId = iDictionary->At(aUid);
+
+	if (streamId == KNullStreamId)
+		{
+		streamId = PersistToStoreL(aUid);
+		}
+	else
+		{
+		ReadFromStoreL(aUid, aRollback);
+		}
+
+	return streamId;
+	}
+
+void CAgnTzRuleIndex::InternalizeRulesL(RReadStream& aStream,
+		TBool aIsSystemRule, TBool aRollback)
+	{
+	TInt count = aStream.ReadInt16L();
+	CAgnTzRuleIndexItem* item= NULL;
+	for (TInt ii=0; ii<count; ++ii)
+		{
+		if (aIsSystemRule)
+			{
+			item = CAgnSystemTzRuleIndexItem::NewL(aStream);
+			}
+		else
+			{
+			item = CAgnTzRuleIndexItem::NewL(aStream);
+			}
+
+		CleanupStack::PushL(item);
+		RStoreReadStream readStream;
+
+		readStream.OpenLC(*iStore, item->StreamId());
+		CTzRules* tzRules = CTzRules::NewL(readStream);
+		item->SetRule(tzRules);
+		CleanupStack::PopAndDestroy(&readStream);
+
+		if (aIsSystemRule)
+			{
+			if (aRollback)
+				{
+				CleanupStack::Pop(item);
+				RollbackItemL(iSystemTzRules, item);
+				}
+			else
+				{
+				iSystemTzRules.AppendL(item);
+				CleanupStack::Pop(item);
+				}
+			}
+		else
+			{
+			if (aRollback)
+				{
+				CleanupStack::Pop(item);
+				RollbackItemL(iUserDefinedTzRules, item);
+				}
+			else
+				{
+				iUserDefinedTzRules.AppendL(item);
+				CleanupStack::Pop(item);
+				}
+			}
+		}
+	}
+
+void CAgnTzRuleIndex::ExternalizeRulesL(RWriteStream& aStream, const RPointerArray<CAgnTzRuleIndexItem>& aArray) const
+	{
+	TInt count = aArray.Count();
+	aStream.WriteInt16L(count);
+
+	for (TInt ii=0; ii<count; ++ii)
+		{
+		aArray[ii]->ExternalizeL(aStream);
+		}
+	}
+
+CAgnTzRuleIndex::~CAgnTzRuleIndex()
+	{
+	iSystemTzRules.ResetAndDestroy();
+	iUserDefinedTzRules.ResetAndDestroy();
+	iTimeZoneAccessor->RemoveSystemTimeObserver(this);
+	CAgnTlsProxy::Release(iTimeZoneAccessor);
+	}
+
+/**
+ It is called when:
+
+ Creating a light entry during index building.
+ Fetch an entry
+
+ @param reference to the entry fetching tz rules
+ */
+void CAgnTzRuleIndex::FetchTzRuleL(CAgnSimpleEntry& aEntry)
+	{
+	CAgnTzRules* tzZone = GetTzRulesFromEntry(aEntry);
+	if (tzZone == NULL)
+		{
+		return;
+		}
+
+	TInt pos = KErrNotFound;
+	if (tzZone->SystemTzRule())
+		{
+		pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(), iSystemTzRules,
+				ETrue);
+		if (pos>=0)
+			{
+			tzZone->SetTzRules(iSystemTzRules[pos]->TzRule());
+			tzZone->SetUseCurrentSystemTzRules((pos == iPosCurSystemTzRule));
+			}
+		}
+	else
+		{
+		__ASSERT_DEBUG(!tzZone->UseCurrentSystemTzRules(), User::Invariant());
+		pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(),
+				iUserDefinedTzRules, ETrue);
+		if (pos>=0)
+			{
+			tzZone->SetTzRules(iUserDefinedTzRules[pos]->TzRule());
+			}
+		}
+
+	if (pos == KErrNotFound)
+		{
+		AddCurrentSystemTzRuleL(*tzZone);
+		}
+	}
+
+/**
+ Remove a tz rule from one of tz rule arraies
+
+ It should be called when an entry is removed or an entry is updated
+
+ @param reference to the entry to be deleted
+ */
+void CAgnTzRuleIndex::RemoveTzRuleL(CAgnSimpleEntry& aEntry)
+	{
+	CAgnTzRules* tzZone = GetTzRulesFromEntry(aEntry);
+	if (tzZone == NULL || !tzZone->HasValidTzZoneStreamId())
+		{
+		return;
+		}
+
+	TInt pos = KErrNotFound;
+	if (tzZone->SystemTzRule())
+		{
+		pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(), iSystemTzRules,
+				EFalse);
+		if (pos >=0)
+			{
+			DeleteARuleL(pos, iSystemTzRules, iSystemRuleStreamId);
+			}
+		}
+	else
+		{
+		pos = FindTzRuleByStreamIdL(tzZone->TzZoneStreamId(),
+				iUserDefinedTzRules, EFalse);
+		if (pos >=0)
+			{
+			DeleteARuleL(pos, iUserDefinedTzRules, iUserDefinedRuleStreamId);
+			}
+		}
+
+	__ASSERT_DEBUG(pos != KErrNotFound, Panic(EAgmErrTzRuleIsNotFound));
+
+	User::LeaveIfError(pos);
+	}
+
+/**
+ Add a tz rule to the array if it is not existing in the array otherwise
+ increase the refference count for that rule.
+
+ It is called when:
+
+ An entry is added with a user defined tz rule
+ An old format file (9.4 prior) is converted to a new format
+
+ @param reference to the entry to be added.
+ */
+void CAgnTzRuleIndex::AddTzRuleL(CAgnEntry& aEntry)
+	{
+	CAgnTzRules* tzZone = GetTzRulesFromEntry(aEntry);
+	if (tzZone == NULL)
+		{
+		return;
+		}
+
+	if (tzZone->TzRules() == NULL || tzZone->UseCurrentSystemTzRules())
+		{
+		AddCurrentSystemTzRuleL(*tzZone);
+		return;
+		}
+
+	TBool isSysRule = EFalse;
+	TInt pos = FindRule(*tzZone->TzRules(), isSysRule);
+	if (pos >= 0)
+		{
+		if (isSysRule)
+			{
+			iSystemTzRules[pos]->IncrementRef();
+			}
+		else
+			{
+			iUserDefinedTzRules[pos]->IncrementRef();
+			}
+
+		}
+	else
+		{
+		CTzRules* tzRule = tzZone->TzRules()->CloneL();
+		CleanupStack::PushL(tzRule);
+		TStreamId streamId = PersistTzRuleL(*tzRule);//It will not be commited until model commit the entry into the file
+		CAgnTzRuleIndexItem* item = CAgnTzRuleIndexItem::NewL(streamId, tzRule);
+		CleanupStack::Pop(tzRule);
+
+		CleanupStack::PushL(item);
+		iUserDefinedTzRules.AppendL(item);
+		pos = iUserDefinedTzRules.Count()-1;
+		CleanupStack::Pop(item);
+		}
+
+	if (isSysRule)
+		{
+		UpdateItemsInStoreL(iSystemTzRules, iSystemRuleStreamId);
+		tzZone->SetTzRules(iSystemTzRules[pos]->TzRule());
+		tzZone->SetSystemTzRule(ETrue);
+		tzZone->SetTzZoneStreamId(iSystemTzRules[pos]->StreamId());
+		}
+	else
+		{
+		UpdateItemsInStoreL(iUserDefinedTzRules, iUserDefinedRuleStreamId);
+		tzZone->SetTzRules(iUserDefinedTzRules[pos]->TzRule());
+		tzZone->SetSystemTzRule(EFalse);
+		tzZone->SetTzZoneStreamId(iUserDefinedTzRules[pos]->StreamId());
+		}
+	}
+
+/**
+ Called when entry's tz rule changed
+
+ @param aOldEntry reference to the original entry to be updated.
+ @param aNewEntry reference to the entry containing updated content.
+ */
+void CAgnTzRuleIndex::UpdateTzRuleL(CAgnEntry& aOldEntry, CAgnEntry& aNewEntry)
+	{
+	CAgnTzRules* newTzZone = GetTzRulesFromEntry(aNewEntry);
+	if (newTzZone != NULL && newTzZone->HasValidTzZoneStreamId())
+		{
+		TInt pos = KErrNotFound;
+		if (newTzZone->SystemTzRule())
+			{
+			pos = FindTzRuleByStreamIdL(newTzZone->TzZoneStreamId(), iSystemTzRules, EFalse);
+			iSystemTzRules[pos]->IncrementRef();
+			newTzZone->SetTzRules(iSystemTzRules[pos]->TzRule());
+			UpdateItemsInStoreL(iSystemTzRules, iSystemRuleStreamId);
+			}
+		else
+			{
+			pos = FindTzRuleByStreamIdL(newTzZone->TzZoneStreamId(), iUserDefinedTzRules, EFalse);
+			iUserDefinedTzRules[pos]->IncrementRef();
+			newTzZone->SetTzRules(iUserDefinedTzRules[pos]->TzRule());
+			UpdateItemsInStoreL(iUserDefinedTzRules, iUserDefinedRuleStreamId);
+			}
+
+		__ASSERT_DEBUG(pos !=KErrNotFound, Panic(EAgmErrTzRuleIsNotFound));
+		}
+	else
+		{
+		AddTzRuleL(aNewEntry);
+		}
+
+	RemoveTzRuleL(aOldEntry);
+	}
+
+void CAgnTzRuleIndex::UpdateItemsInStoreL(
+		RPointerArray<CAgnTzRuleIndexItem>& aArray, TStreamId aStreamId)
+	{
+	RStoreWriteStream writeStream;
+	writeStream.ReplaceLC(*iStore, aStreamId);
+	ExternalizeRulesL(writeStream, aArray);
+	writeStream.CommitL();
+	CleanupStack::PopAndDestroy(&writeStream);
+	}
+
+TInt CAgnTzRuleIndex::FindTzRuleByStreamIdL(TStreamId aStreamId, RPointerArray<CAgnTzRuleIndexItem>& aArray, TBool aTryPosLastTime)
+	{
+	TInt count = aArray.Count();
+	if (aTryPosLastTime && iPosFetchedLastTime >= 0 && count
+			> iPosFetchedLastTime)
+		{
+		if (aStreamId == aArray[iPosFetchedLastTime]->StreamId())
+			{
+			return iPosFetchedLastTime;
+			}
+		}
+
+	TInt pos = KErrNotFound;
+	TInt ii = 0;
+	while (pos == KErrNotFound && ii < count)
+		{
+		if (aStreamId == aArray[ii]->StreamId())
+			{
+			pos = ii;
+			}
+		++ii;
+		}
+
+	if (aTryPosLastTime)
+		{
+		iPosFetchedLastTime = pos;
+		}
+
+	return pos;
+	}
+
+TInt CAgnTzRuleIndex::FindRule(RPointerArray<CAgnTzRuleIndexItem>& aRuleArray, const CTzRules& aRule)
+	{
+	TInt pos = KErrNotFound;
+	TInt count = aRuleArray.Count();
+	TInt ii = 0;
+	while (pos < 0 && ii<count)
+		{
+		if (aRule.IsEqualTo(*(aRuleArray[ii]->TzRule())))
+			{
+			pos = ii;
+			}
+		++ii;
+		}
+
+	return pos;
+	}
+
+TInt CAgnTzRuleIndex::FindRule(const CTzRules& aTzRule, TBool& aIsSystemRule)
+	{
+	TInt pos = KErrNotFound;
+	pos = FindRule(iSystemTzRules, aTzRule);
+	if (pos>=0)
+		{
+		aIsSystemRule = ETrue;
+		}
+	else
+		{
+		pos = FindRule(iUserDefinedTzRules, aTzRule);
+		if (pos>=0)
+			{
+			aIsSystemRule = EFalse;
+			}
+		}
+	return pos;
+	}
+
+/**
+ Add the current system tz rule to the array if it is not there otherwise
+ increase the refference count for the rule.
+
+
+ It is called when:
+
+ An entry is added with the current tz rule
+ @param reference to a CAgnTzRules object which is added to the index
+ */
+void CAgnTzRuleIndex::AddCurrentSystemTzRuleL(CAgnTzRules& aTzZone)
+	{
+	if (iPosCurSystemTzRule >= 0)
+		{
+		iSystemTzRules[iPosCurSystemTzRule]->IncrementRef();
+		}
+	else
+		{
+		RTz& tzServer = iTimeZoneAccessor->TzServer();
+		CTzId* tzId = tzServer.GetTimeZoneIdL();
+		CleanupStack::PushL(tzId);
+		CTzRules* rule = tzServer.GetTimeZoneRulesL(*tzId, KMinYear, KMaxYear, ETzUtcTimeReference);
+		CleanupStack::PushL(rule);
+		TStreamId streamId = PersistTzRuleL(*rule);//It will not be commited until model commit the entry into the file
+		CAgnSystemTzRuleIndexItem* item = CAgnSystemTzRuleIndexItem::NewL(streamId, tzId->TimeZoneNameID(), rule);
+		CleanupStack::Pop(rule);
+		CleanupStack::PushL(item);
+		iSystemTzRules.AppendL(item);
+		iPosCurSystemTzRule = iSystemTzRules.Count()-1;
+		CleanupStack::Pop(item);
+
+		CleanupStack::PopAndDestroy(tzId);
+		}
+
+	UpdateItemsInStoreL(iSystemTzRules, iSystemRuleStreamId);
+	aTzZone.SetTzZoneStreamId(iSystemTzRules[iPosCurSystemTzRule]->StreamId());
+	aTzZone.SetTzRules(iSystemTzRules[iPosCurSystemTzRule]->TzRule());
+	aTzZone.SetSystemTzRule(ETrue);
+	aTzZone.SetUseCurrentSystemTzRules(ETrue);
+	}
+
+void CAgnTzRuleIndex::DeleteARuleL(TInt aPos, RPointerArray<CAgnTzRuleIndexItem>& aArray, TStreamId aStreamId)
+	{
+	TInt ref = aArray[aPos]->DecrementRef();
+	if (ref ==0)
+		{
+		iStore->DeleteL(aArray[aPos]->StreamId());
+		delete aArray[aPos];
+		aArray.Remove(aPos);
+
+		if (aPos == iPosCurSystemTzRule)
+			{
+			iPosCurSystemTzRule = KErrNotFound;
+			}
+		else if (aPos < iPosCurSystemTzRule)
+			{
+			--iPosCurSystemTzRule;
+			}
+		}
+
+	UpdateItemsInStoreL(aArray, aStreamId);
+	}
+
+TStreamId CAgnTzRuleIndex::PersistTzRuleL(const CTzRules& aTzRule)
+	{
+	TStreamId streamId = iStore->ExtendL();
+	RStoreWriteStream writeStream;
+	writeStream.ReplaceLC(*iStore, streamId);
+	aTzRule.ExternalizeL(writeStream);
+	writeStream.CommitL();//Don't commit to store until the CAgnEntryModel does it
+	CleanupStack::PopAndDestroy(&writeStream);
+	return streamId;
+	}
+
+void CAgnTzRuleIndex::HandleCurrentTimeZoneChangeL(const CTzId& aSystemTzId)
+	{
+	if (iPosCurSystemTzRule != KErrNotFound && 0 == static_cast<CAgnSystemTzRuleIndexItem*>(iSystemTzRules[iPosCurSystemTzRule])->TzId().Compare(aSystemTzId.TimeZoneNameID()))
+		{
+		//the rule doesn't change.
+		return;
+		}
+
+	CTzRules* rule = iTimeZoneAccessor->GetCurrentSystemTzRulesL();
+	CleanupStack::PushL(rule);
+	iPosCurSystemTzRule = FindRule(iSystemTzRules, *rule);
+	CleanupStack::PopAndDestroy(rule);
+	}
+
+void CAgnTzRuleIndex::HandleTzRulesChangeL(const TTime& aTime)
+	{
+	if(!iAgnFile->IsLocked())
+	    {
+        if (iTzDbChangeTimeStamp < aTime)
+            {
+            iTzDbChangeTimeStamp = aTime;
+            if (RefreshTzRulesL())
+                {
+                iTzRulesLastModifiedTime = aTime;
+                }
+            WriteTimeStampL();
+            }
+	    }
+	else // set the flag so that it can be done later when agendar server is unlocked.
+	    {
+	    iAgnFile->SetRefreshTzRules(ETrue);
+	    }
+	}
+
+/* Refresh cached system tz rules and broadcast the change if any of rules has been updated
+ */
+TBool CAgnTzRuleIndex::RefreshTzRulesL()
+	{
+	TBool rulesChanged = EFalse;
+	const TInt KCount = iSystemTzRules.Count();
+	for (TInt ii = 0; ii<KCount; ++ii)
+		{
+		CTzId* id = CTzId::NewL(static_cast<CAgnSystemTzRuleIndexItem*>(iSystemTzRules[ii])->TzId());
+		CTzRules* rules= NULL;
+		TRAPD(err, rules = iTimeZoneAccessor->TzServer().GetTimeZoneRulesL(*id, KMinYear, KMaxYear , ETzUtcTimeReference));
+		delete id;
+		if(err == KErrNone)
+		    {
+            CleanupStack::PushL(rules);
+            if (rules && !iSystemTzRules[ii]->TzRule()->IsEqualTo(*rules))
+                {//If a tz rule cached is different from the one in tz server for the same TZ ID, it needs to be updated with the new one.
+                CAgnTzRuleIndexItem* item = iSystemTzRules[ii];
+                item->TzRule()->CopyL(*rules);
+                RStoreWriteStream writeStream;
+                writeStream.ReplaceLC(*iStore, item->StreamId());
+                item->TzRule()->ExternalizeL(writeStream);
+                writeStream.CommitL();
+                CleanupStack::PopAndDestroy(&writeStream);
+                iStore->CommitL();
+                rulesChanged = ETrue;
+                }
+            CleanupStack::PopAndDestroy(rules);
+            }
+		}
+	if (rulesChanged)
+		{
+		iAgnFile->TzRulesHaveChangedL();
+		}
+	return rulesChanged;
+	}
+
+void CAgnTzRuleIndex::RollBackL()
+	{
+	ReadItemsFromStoreL(KUidAgnSystemTzIndex, ETrue);
+	ReadItemsFromStoreL(KUidAgnImportedTzIndex, ETrue);
+	}
+
+void CAgnTzRuleIndex::ReloadStore(CStreamDictionary& aDictionary, CFileStore& aStore)
+	{
+	iDictionary = &aDictionary;
+	iStore = &aStore;
+	}
+
+CTzRules* CAgnTzRuleIndex::FindTzRuleByStreamIdL(TStreamId aStreamId, TBool aIsSystemRule)
+	{
+	CTzRules* tzRules= NULL;
+	if (aIsSystemRule)
+		{
+		TInt pos = FindTzRuleByStreamIdL(aStreamId, iSystemTzRules, EFalse);
+		if (pos != KErrNotFound)
+			{
+			tzRules = iSystemTzRules[pos]->TzRule()->CloneL();
+			}
+		}
+	else
+		{
+		TInt pos = FindTzRuleByStreamIdL(aStreamId, iUserDefinedTzRules, EFalse);
+		if (pos != KErrNotFound)
+			{
+			tzRules = iUserDefinedTzRules[pos]->TzRule()->CloneL();
+			}
+		}
+
+	if (tzRules == NULL)
+		{
+		tzRules = iTimeZoneAccessor->GetCurrentSystemTzRulesL();
+		}
+
+	return tzRules;
+	}
+
+CAgnTzRules* CAgnTzRuleIndex::GetTzRulesFromEntry(CAgnSimpleEntry& aEntry)
+	{
+	CAgnTzRules* tzZone= NULL;
+	if (aEntry.TimeMode() != MAgnCalendarTimeMode::EFloating)
+		{
+		CAgnRptDef* rptDef = aEntry.RptDef();
+		if (rptDef != NULL)
+			{
+			tzZone = rptDef->AgnTzRules();
+			}
+		}
+
+	return tzZone;
+	}
+
+void CAgnTzRuleIndex::RollbackItemL(RPointerArray<CAgnTzRuleIndexItem>& aRuleArray,	CAgnTzRuleIndexItem* aItem)
+	{
+	CleanupStack::PushL(aItem);
+	TInt pos = FindTzRuleByStreamIdL(aItem->StreamId(), aRuleArray, EFalse);
+	if (pos == KErrNotFound)
+		{
+		aRuleArray.AppendL(aItem);
+		CleanupStack::Pop(aItem);
+		}
+	else
+		{
+		CAgnTzRuleIndexItem* item = aRuleArray[pos];
+		item->SetReferenceCount(aItem->ReferenceCount());
+		CleanupStack::PopAndDestroy(aItem);
+		}
+	}
+
+/** Get the last modified time for tz rules
+ * It is called when the client getting the last modified date for an entry since the
+ * last modified time of an entry is not updated when tz database is updated.
+*/
+TTime CAgnTzRuleIndex::TzRulesLastModifiedDateL()
+	{
+	return iTzRulesLastModifiedTime;
+	}