// Copyright (c) 2005-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 "calentryimpl.h"

#include "calclient.h"
#include "agsalarm.h"
#include "agmattachment.h"
#include "agmdate.h"
#include "agmentry.h"
#include "agmpanic.h"
#include "agmcategory.h"
#include "agmattendee.h"
#include "agmcontent.h"
#include <calalarm.h>
#include "calcategoryimpl.h"
#include <calcontent.h>
#include <calrrule.h>
#include <calsession.h>
#include "calsessionimpl.h"
#include "caluserimpl.h"

const TInt KAttendeeGranularity = 2;
const TInt KCategoryGranularity = 1;
const TInt KAttachmentGranularity = 1;


CCalEntryImpl::~CCalEntryImpl()
	{
	if(iSessionImpl)
		{
		iSessionImpl->DecrementReferenceCount();
		}

	if (iLiteEntry)
 		{
		iLiteEntry->DecrementRefCount();
 		}
	if(iCalAttachmentList)
		{
		iCalAttachmentList->ResetAndDestroy();
		delete iCalAttachmentList; 	
		}
	if(iCalAttendeeList)
		{
		iCalAttendeeList->ResetAndDestroy();
		delete iCalAttendeeList;
		}
	if(iCalCategoryList)
		{
		iCalCategoryList->ResetAndDestroy();
		delete iCalCategoryList;
		}
	delete iCalOrganizer;
	delete iFullEntry;
	}

CCalEntryImpl::CCalEntryImpl()
	{
	}

CCalEntryImpl::CCalEntryImpl(CAgnEntry& aEntry, CCalSessionImpl& aSessionImpl)
	: iFullEntry(&aEntry), iSessionImpl(&aSessionImpl)
	{
	iSessionImpl->IncrementReferenceCount();
	}


CCalEntryImpl::CCalEntryImpl(CCalLiteEntry& aEntry, CCalSessionImpl& aSessionImpl)
	: iLiteEntry(&aEntry), iSessionImpl(&aSessionImpl)
 	{
 	iSessionImpl->IncrementReferenceCount();
	iLiteEntry->IncrementRefCount();
 	}

void CCalEntryImpl::ClearSimpleEntry()
	{
	if (iSessionImpl && iLiteEntry)
		{
		iLiteEntry->DecrementRefCount();
		iLiteEntry = NULL;
		}
	}
	
CCalEntryImpl* CCalEntryImpl::NewL(CCalEntry::TType aType, HBufC8* aUid, CCalEntry::TMethod aMethod, TUint aSeqNum)
	{
	__ASSERT_ALWAYS(aUid && aUid->Length() > 0, User::Leave(KErrArgument));

	CCalEntryImpl* self = new (ELeave) CCalEntryImpl();
	CleanupStack::PushL(self);
	self->ConstructL(aType, aUid, aMethod, aSeqNum); // takes ownership of aUid
	CleanupStack::Pop(self);
	return self;
	}

CCalEntryImpl* CCalEntryImpl::NewL(CCalEntry::TType aType, HBufC8* aUid, CCalEntry::TMethod aMethod,
			TUint aSeqNum, const TCalTime& aRecurrenceId, CalCommon::TRecurrenceRange aRange)
	{
	__ASSERT_ALWAYS(aUid && aUid->Length() > 0, User::Leave(KErrArgument));

	CCalEntryImpl* self = new (ELeave) CCalEntryImpl();
	CleanupStack::PushL(self);
	self->ConstructL(aType, aUid, aMethod, aSeqNum, CalUtils::TCalTimeToTAgnCalendarTimeL(aRecurrenceId), aRange);
	   // takes ownership of aUid
	CleanupStack::Pop(self);
	return self;
	}

CCalEntryImpl* CCalEntryImpl::NewL(CAgnEntry& aEntry, CCalSessionImpl& aSessionImpl)
	{
	CCalEntryImpl* self = new (ELeave) CCalEntryImpl(aEntry, aSessionImpl);
	return self;
	}

CCalEntryImpl* CCalEntryImpl::NewL(CCalLiteEntry& aEntry, CCalSessionImpl& aSessionImpl)
	{
	CCalEntryImpl* self = new (ELeave) CCalEntryImpl(aEntry, aSessionImpl);
	return self;
	}

void CCalEntryImpl::ConstructL(CCalEntry::TType aType, HBufC8* aUid, CCalEntry::TMethod aMethod, TUint aSeqNum, const TAgnCalendarTime& aRecurrenceId, CalCommon::TRecurrenceRange aRange)
	{
	// Create appropriate CAgnEntry type child entry.
	iFullEntry = CAgnEntry::NewL(aType, aUid, aMethod, aSeqNum, aRecurrenceId, aRange); // takes ownership of aUid
	}


void CCalEntryImpl::ConstructL(CCalEntry::TType aType, HBufC8* aUid, CCalEntry::TMethod aMethod, TUint aSeqNum)
	{
	// Create appropriate CAgnEntry type parent entry.
	iFullEntry = CAgnEntry::NewL(aType, aUid, aMethod,aSeqNum);
	}

void CCalEntryImpl::LoadFullEntryL()
	{
	if (iLiteEntry)
		{
		// iFullEntry should be NULL at this point
		__ASSERT_DEBUG(iFullEntry == NULL, User::Leave(KErrCorrupt));
		
		// extract full CAgnEntry from TAgnLiteEntry and store it in iFullEntry
		TCalLocalUid id = iLiteEntry->LiteEntry().LocalUid();
		iFullEntry = iSessionImpl->Server().FetchEntryL(id, iSessionImpl->FileId());
		__ASSERT_ALWAYS(iFullEntry, User::Leave(KErrNotFound));
		iFullEntry->SetCollectionId(iLiteEntry->LiteEntry().CollectionId());
		ClearSimpleEntry();
		}
	}

// return the CAgnEntry associated with this entry, loading it from the server if necessary
CAgnEntry* CCalEntryImpl::GetFullEntryL()
	{
	LoadFullEntryL();
	return iFullEntry;
	}

void CCalEntryImpl::PopulateCategoryListL()
	{
	if (!iCalCategoryList)
		{
		LoadFullEntryL();
		iCalCategoryList = new (ELeave) RPointerArray<CCalCategory>(KCategoryGranularity);

		const TInt KCategoryCount = iFullEntry->CategoryCount();
		for (TInt i = 0; i < KCategoryCount; ++i)
			{
			CAgnCategory& agnCategory = iFullEntry->FetchCategory(i); // ownership not taken
			CCalCategoryImpl* impl = CCalCategoryImpl::NewL(&agnCategory); // doesn't take ownership of agnCategory
			CleanupStack::PushL(impl);
			CCalCategory* category = CCalCategory::NewL(impl); // takes ownership of impl
			CleanupStack::Pop(impl);
			CleanupStack::PushL(category);
			iCalCategoryList->AppendL(category); // takes ownership of category
			CleanupStack::Pop(category);
			}
		}
	}

void CCalEntryImpl::PopulateAttendeeListL()
	{
	if(!iCalAttendeeList)
		{
		LoadFullEntryL();

		iCalAttendeeList = new(ELeave) RPointerArray<CCalAttendee>(KAttendeeGranularity);

		const TInt KAttendeeCount = iFullEntry->AttendeeCount();
		for(TInt i = 0; i < KAttendeeCount; ++i)
			{
			CAgnAttendee& agnAttendee = iFullEntry->FetchAttendee(i);
			
			CCalUserImpl* impl = CCalUserImpl::NewL(&agnAttendee);	// doesn't take ownership of agnAttendee
			CleanupStack::PushL(impl);
			CCalAttendee* calAttendee = CCalAttendee::NewL(impl);	// takes ownership of impl
			CleanupStack::Pop(impl);
			
			CleanupStack::PushL(calAttendee);
			iCalAttendeeList->AppendL(calAttendee);
			CleanupStack::Pop(calAttendee);
			}
		}
	}


void CCalEntryImpl::AddAttendeeL(CCalAttendee* aAttendee)
	{
    if (!aAttendee)
        {
        User::Leave( KErrArgument );
        }

	CleanupStack::PushL(aAttendee);
	__ASSERT_ALWAYS(aAttendee != NULL, User::Leave(KErrArgument));
	PopulateAttendeeListL();

	CCalUserImpl* userImpl = aAttendee->Impl();
	CAgnAttendee* attendee = userImpl->Attendee();
	
	// add attendee to CAgnEntry (no longer owned by CCalAttendee)
	userImpl->SetOwnsCAgnAttendee(EFalse);		
	iFullEntry->AddAttendeeL(attendee);		
	
	// store attendee in attendee array too
	iCalAttendeeList->AppendL(aAttendee);
	CleanupStack::Pop(aAttendee);
	}

RPointerArray<CCalAttendee>& CCalEntryImpl::AttendeesL()
	{
	PopulateAttendeeListL();
	return *iCalAttendeeList;
	}

void CCalEntryImpl::DeleteAttendeeL(TInt aIndex)
	{
	LoadFullEntryL();

	if(iCalAttendeeList)
		{
		if (aIndex < 0 || aIndex >= iCalAttendeeList->Count())
			{
			User::Leave(KErrArgument);
			}
		delete (*iCalAttendeeList)[aIndex];
		iCalAttendeeList->Remove(aIndex);
		}

	iFullEntry->DeleteAttendee(aIndex);
	}

void CCalEntryImpl::SetOrganizerL(CCalUser* aUser)
	{
	CleanupStack::PushL(aUser);
	__ASSERT_ALWAYS(aUser != NULL, User::Leave(KErrArgument));
	LoadFullEntryL();
	
	aUser->Impl()->SetOwnsCAgnAttendee(EFalse);
	iFullEntry->SetOrganizerL(aUser->Impl()->Attendee());	//	takes ownership of user immediately

	delete iCalOrganizer;
	iCalOrganizer = aUser;
	CleanupStack::Pop(aUser);
	}

void CCalEntryImpl::SetPhoneOwnerL(const CCalUser* aOwner)
	{
	__ASSERT_ALWAYS(aOwner != NULL, User::Leave(KErrArgument));
	LoadFullEntryL();
	CCalUserImpl* userImpl = aOwner->Impl();
	iFullEntry->SetPhoneOwnerL(userImpl->Attendee());
	}

CCalUser* CCalEntryImpl::PhoneOwnerL()
	{
	LoadFullEntryL();

	CAgnAttendee* agnPhoneOwner = iFullEntry->PhoneOwner();

	if(agnPhoneOwner)
		{	
		//check to see if phone owner is the organizer
		if(OrganizerL())
			{
			if(agnPhoneOwner == iCalOrganizer->Impl()->Attendee())
				{
				return iCalOrganizer;
				}
			}

		PopulateAttendeeListL();
		
		// see if the phone owner is one of the other attendees
		const TInt KAttendeeCount = iCalAttendeeList->Count();
		for(TInt i = 0; i < KAttendeeCount; ++i)
			{
			CCalAttendee* calAttendee = (*iCalAttendeeList)[i];
			if(agnPhoneOwner == calAttendee->Impl()->Attendee())
				{
				return calAttendee;
				}
			}
		}
	return NULL;
	}


CCalUser* CCalEntryImpl::OrganizerL()
	{
	LoadFullEntryL();
	if( ! iCalOrganizer)
		{
		CAgnAttendee* organizer = iFullEntry->Organizer();
		
		if(organizer)
			{
			CCalUserImpl* impl = CCalUserImpl::NewL(organizer);
			CleanupStack::PushL(impl);
			impl->SetOwnsCAgnAttendee(EFalse);
			iCalOrganizer = CCalUser::NewL(impl);
			CleanupStack::Pop(impl);
			}
		}

	return iCalOrganizer;
	}

CTzRules* CCalEntryImpl::GetTzRulesL()
	{
	CAgnRptDef* rptDef = SimpleEntry()->RptDef();
	
	if (rptDef == NULL)
		{
		return NULL;
		}
	return rptDef->CloneTzRulesL();
	}

void CCalEntryImpl::SetTzRulesL(const CTzRules& aTzRules)
	{
	LoadFullEntryL();
	
	if (TimeMode() == MAgnCalendarTimeMode::EFloating)
		{
		User::Leave(KErrArgument);
		}

	CAgnRptDef* rptDef = SimpleEntry()->RptDef(); // doesn't take ownership
	
	if (!rptDef)
		{
		User::Leave(KErrNotFound);
		}
   
	rptDef->SetTimeZoneL(aTzRules); // rptDef doesn't take ownership of aTzRules
	}

void CCalEntryImpl::SetTzRulesL()
	{
	LoadFullEntryL();
	
	if (TimeMode() == MAgnCalendarTimeMode::EFloating)
		{
		User::Leave(KErrArgument);
		}

	CAgnRptDef* rptDef = SimpleEntry()->RptDef();
	if (rptDef == NULL)
		{
		User::Leave(KErrNotFound);
		}
	rptDef->SetTimeZoneL();
	}

void CCalEntryImpl::SetRDatesL(const RArray<TCalTime>& aRDates)
	{
	LoadFullEntryL();
	SetDatesL(ETrue, aRDates);
	}

void CCalEntryImpl::SetExceptionDatesL(const RArray<TCalTime>& aExDates)
	{
	LoadFullEntryL();
	
	if (iFullEntry->RptDef() == NULL)
		{
		User::Leave(KErrNotFound);
		}

	SetDatesL(EFalse, aExDates);
	}
	
//if aDateType is ETrue, add dates to sporadic date list
//if aDateType is EFalse, add dates to exception list
void CCalEntryImpl::SetDatesL(TBool aDateType, const RArray<TCalTime>& aDates)
	{
	const TCalTime::TTimeMode KEntryTimeMode = static_cast<TCalTime::TTimeMode>(TimeMode());
	const TInt KDateCount = aDates.Count();
	TInt i = 0;
	for (i = 0; i < KDateCount; i++)
		{
		if (aDates[i].TimeMode() != KEntryTimeMode)
			{
			User::Leave(KErrArgument);
			}
		}

	CAgnRptDef* rptDef = SimpleEntry()->RptDef();

	TBool entryHasNoRptDef(rptDef == NULL);
	if (entryHasNoRptDef)
		{
		rptDef = CAgnRptDef::NewL(*SimpleEntry());
		CleanupStack::PushL(rptDef);
		}
	else
		{
		if (aDateType)
			{
			rptDef->RemoveAllSporadicDates();
			}
		else
			{
			rptDef->RemoveAllExceptions();
			}
		}

	// store the dates
	for (i = 0; i < KDateCount; ++i)
		{
		TAgnCalendarTime agnTime = CalUtils::TCalTimeToTAgnCalendarTimeL(aDates[i]);
		if (aDateType)
			{
			rptDef->AddSporadicDateL(agnTime);
			}
		else
			{
			rptDef->AddExceptionL(agnTime);
			}
		}

	// if the rptDef didn't exist in the entry already, add it
	if (entryHasNoRptDef)
		{
		iFullEntry->SetRptDefL(*rptDef); // makes a copy of rptDef
		CleanupStack::PopAndDestroy(rptDef);
		}
	}

void CCalEntryImpl::GetRDatesL(RArray<TCalTime>& aRDates)
	{
	aRDates.Reset();
	const CAgnRptDef* KRptDef = SimpleEntry()->RptDef();
	if (KRptDef)
		{
		FetchDatesL(KRptDef->SporadicDateList(), aRDates);
		}
	}

void CCalEntryImpl::GetExceptionDatesL(RArray<TCalTime>& aExDates)
	{
	aExDates.Reset();
	const CAgnRptDef* KRptDef = SimpleEntry()->RptDef();
	if (KRptDef)
		{
		FetchDatesL(KRptDef->Exceptions(), aExDates);
		}
	}
	
void CCalEntryImpl::FetchDatesL(const RArray<TAgnCalendarTime>* aDateList, RArray<TCalTime>& aRDates)
	{
	// aDateList may be NULL
	if (aDateList)
		{
		const TInt KDateCount = aDateList->Count();
		for (TInt i = 0; i < KDateCount; ++i)
			{
			TCalTime calTime = CalUtils::TAgnCalendarTimeToTCalTimeL((*aDateList)[i]);
			aRDates.AppendL(calTime);
			}
		}
	}

CCalEntry::TMethod CCalEntryImpl::MethodL()
	{
	LoadFullEntryL();
	return iFullEntry->Method();
	}
	
TCalTime CCalEntryImpl::RecurrenceIdL()
	{
	// If this entry has been committed to store, the Rec-Id can be retrieved from the
	// CAgnEntryModel by passing the appropraite CAgnEntry.
	// Else try to retrieve it from CAgnEntry's temporary GS data.

	LoadFullEntryL();
	return CalUtils::TAgnCalendarTimeToTCalTimeL(iFullEntry->RecurrenceId());
	}
	
CalCommon::TRecurrenceRange CCalEntryImpl::RecurrenceRangeL()
   	{
   	LoadFullEntryL();
	return iFullEntry->RecurrenceRange();
   	}
	
const TDesC8& CCalEntryImpl::UidL()
	{
	LoadFullEntryL();
	// Does not transfer ownership
	if(iFullEntry->Guid() == KNullDesC8)
		{
		// this entry must be a child entry whose GUID has not been loaded
		__ASSERT_ALWAYS(iFullEntry->GsDataType() == CGsData::EChild, User::Leave(KErrCorrupt)); 
		
		// get parent entry
		TCalLocalUid parentId = iFullEntry->ParentId();
		CAgnEntry* parentEntry = iSessionImpl->Server().FetchEntryL(parentId, iSessionImpl->FileId());
		__ASSERT_ALWAYS(parentEntry, User::Leave(KErrNotFound));
		CleanupStack::PushL(parentEntry);
		HBufC8* guidHbuf = parentEntry->Guid().AllocL();
		CleanupStack::PopAndDestroy(parentEntry);	

		iFullEntry->SetGuid(guidHbuf);
		}
		
	return iFullEntry->Guid();
	}


TInt CCalEntryImpl::SequenceNumberL()
	{
	LoadFullEntryL();
	return iFullEntry->SequenceNumber();
	}


void CCalEntryImpl::SetMethodL(CCalEntry::TMethod aMethod)
	{
	LoadFullEntryL();
	iFullEntry->SetMethod(aMethod);
	}

const RPointerArray<CCalCategory>& CCalEntryImpl::CategoryListL()
	{
	PopulateCategoryListL();

	return *iCalCategoryList;
	}

void CCalEntryImpl::AddCategoryL(CCalCategory* aCategory)
	{
	CleanupStack::PushL(aCategory);
	__ASSERT_ALWAYS(aCategory != NULL, User::Leave(KErrArgument));
	
 	PopulateCategoryListL();

	// add the category to the list
 	iCalCategoryList->AppendL(aCategory);
	CleanupStack::Pop(aCategory);

	TInt err(KErrNone);

	// add category to CAgnEntry
	TRAP(err , iFullEntry->AddCategoryL( aCategory->Impl()->AgnCategory() ) ); // this can leave before taking ownership

 	if (err != KErrNone)
 		{
 		delete (*iCalCategoryList)[iCalCategoryList->Count() - 1];
 		iCalCategoryList->Remove(iCalCategoryList->Count() - 1);
 		User::Leave(err);
 		}

 	aCategory->Impl()->SetOwnAgnCategory(EFalse);
	}

void CCalEntryImpl::DeleteCategoryL(TInt aIndex)
	{
	LoadFullEntryL();
	
	if (aIndex < 0 || aIndex >= iFullEntry->CategoryCount())
		{
		User::Leave(KErrArgument);
		}
			
	iFullEntry->DeleteCategory(aIndex);
	if(iCalCategoryList)
		{
		delete (*iCalCategoryList)[aIndex];
		iCalCategoryList->Remove(aIndex);
		
		// check count of CAgnCategory and CCalCategory is the same
		__ASSERT_DEBUG(iCalCategoryList->Count() == iFullEntry->CategoryCount(), Panic(EAgmErrCategoryCountCorrupt)); 
		}
	}

TBool CCalEntryImpl::GetRRuleL(TCalRRule& aRule)
	{
	const CAgnRptDef* KRptDef = SimpleEntry()->RptDef();
	if (KRptDef == NULL || KRptDef->RRule() == NULL)
		{
		return EFalse;
		}

	const TAgnRpt* KRpt = KRptDef->RRule();

	// get the DTSTART property
	if (SimpleEntry()->Type() == CCalEntry::ETodo)
		{
		aRule.SetDtStart(EndTimeL());
		}
	else
		{
		aRule.SetDtStart(StartTimeL());
		}

	TInt repCount = 0;
	TCalTime untilCaltime = CalUtils::TAgnCalendarTimeToTCalTimeL(KRpt->UntilTimeL());
		
	if (untilCaltime.TimeLocalL() == TCalTime::MaxTime())
		{
		//Idealy, only UTC maximum time should be used to indicate the repeating forever. However, for a behaviour compatible reason,
		//when the client sets local or UTC repeating until time to be maximum time, it is treated as repeating forever. 
		untilCaltime.SetTimeUtcL(TCalTime::MaxTime());
		}
	else
		{
		repCount = KRpt->InstanceCountL();
		}

	aRule.SetUntilAndCount(untilCaltime, repCount);	
	
	// get the INTERVAL property
	aRule.SetInterval(KRpt->Interval());

	// get the TCalRRule's type, and type-specific data
	switch (KRpt->Type())
		{
		case TAgnRpt::EDaily:
			aRule.SetType(TCalRRule::EDaily);
			break;
		case TAgnRpt::EYearlyByDate:
			aRule.SetType(TCalRRule::EYearly);
			break;
		case TAgnRpt::EYearlyByDay:
			{
			aRule.SetType(TCalRRule::EYearly);

			TDay day;
			TAgnRpt::TWeekInMonth weekInMonth;
			TMonth month;
			TInt year;

			const TAgnYearlyByDayRpt* KYearlyRpt = static_cast<const TAgnYearlyByDayRpt*>(KRpt);
			KYearlyRpt->GetStartDayL(day, weekInMonth, month, year);
			TInt8 week = CalUtils::AgnWeekInMonthToWeekNumberL(weekInMonth);
			TCalRRule::TDayOfMonth dayOfMonth(day, week);

			RArray<TCalRRule::TDayOfMonth> dayOfMonthArray;
			CleanupClosePushL(dayOfMonthArray);
			dayOfMonthArray.AppendL(dayOfMonth);
			aRule.SetByDay(dayOfMonthArray);
			CleanupStack::PopAndDestroy(&dayOfMonthArray);

			RArray<TMonth> monthArray;
			CleanupClosePushL(monthArray);
			monthArray.AppendL(month);
			aRule.SetByMonth(monthArray);
			CleanupStack::PopAndDestroy(&monthArray);
			}
			break;
		case TAgnRpt::EWeekly:
			{
			aRule.SetType(TCalRRule::EWeekly);
			const TAgnWeeklyRpt* KWeeklyRpt = static_cast<const TAgnWeeklyRpt*>(KRpt);
			aRule.SetWkSt(KWeeklyRpt->FirstDayOfWeek());

			RArray<TDay> array;
			CleanupClosePushL(array);
			TDay day = EMonday;
			while (day <= ESunday)
				{
				if (KWeeklyRpt->IsDaySet(day))
					{
					array.AppendL(day);
					}
				day = static_cast<TDay>(static_cast<TInt>(day) + 1);
				}
			aRule.SetByDay(array);
			CleanupStack::PopAndDestroy(&array);
			}
			break;
		case TAgnRpt::EMonthlyByDays:
			{
			aRule.SetType(TCalRRule::EMonthly);
			const TAgnMonthlyByDaysRpt* KMonthlyByDayRpt = static_cast<const TAgnMonthlyByDaysRpt*>(KRpt);

			RArray<TCalRRule::TDayOfMonth> dayArray;
			CleanupClosePushL(dayArray);
			
			TAgnRpt::TWeekInMonth week = TAgnRpt::EFirst;
			while (week <= TAgnRpt::ELast)
				{
				TDay day = EMonday;
				while (day <= ESunday)
					{
					if (KMonthlyByDayRpt->IsDaySet(day, week))
						{
						TInt8 weekInt = CalUtils::AgnWeekInMonthToWeekNumberL(week);
						TCalRRule::TDayOfMonth dayOfMonth(day, weekInt);
						dayArray.AppendL(dayOfMonth);
						}
					day = static_cast<TDay>(static_cast<TInt>(day) + 1);
					}
			
				week = static_cast<TAgnRpt::TWeekInMonth>(static_cast<TInt>(week) + 1);
				}
			//coverity [dead_error_begin]
			aRule.SetByDay(dayArray);

			CleanupStack::PopAndDestroy(&dayArray); // dayArray.Close()
			}
			break;
		case TAgnRpt::EMonthlyByDates:
			{
			aRule.SetType(TCalRRule::EMonthly);
			const TAgnMonthlyByDatesRpt* KMonthlyByDateRpt = static_cast<const TAgnMonthlyByDatesRpt*>(KRpt);

			RArray<TInt> array;
			CleanupClosePushL(array);
			for (TInt i = 0; i < 31; ++i) // dates run from 0 to 30
				{
				if (KMonthlyByDateRpt->IsDateSet(i))
					{
					array.AppendL(i);
					}
				}
			aRule.SetByMonthDay(array);
			CleanupStack::PopAndDestroy(&array);
			}
			break;
		default:
			CalUtils::Panic(EInvalidRepeatRuleType);
			break;
		}

	return ETrue;
	}

TBool CCalEntryImpl::CompareL(const CCalEntry& aEntry)
	{
	// load full CAgnEntries before comparison
	LoadFullEntryL();
	aEntry.Impl()->LoadFullEntryL();
	
	// Load both entry's summary, description and alarm action data before comparing - these properties
	// are stored in separate streams so may not be loaded at this point
	SummaryL();
	aEntry.SummaryL();
	DescriptionL();
	aEntry.DescriptionL();
	delete AlarmL();
	delete aEntry.AlarmL();
	
	return (iFullEntry->CompareL(*aEntry.Impl()->GetFullEntryL()));
	}

void CCalEntryImpl::CopyFromL(CCalEntryImpl& aOther, CCalEntry::TCopyType aCopyType)
	{
	TCalCollectionId collectionId = 0;
	if (iLiteEntry)
		{
		TUint8 collectionId = aOther.SimpleEntry()->CollectionId();
		}
	aOther.LoadFullEntryL();
	// Delete old state.
	ClearSimpleEntry();

	if(iCalAttendeeList)
		{
		iCalAttendeeList->ResetAndDestroy();
		delete iCalAttendeeList; 	
		iCalAttendeeList = NULL;
		}

	if(iCalCategoryList)
		{
		iCalCategoryList->ResetAndDestroy();
		delete iCalCategoryList; 
		iCalCategoryList = NULL;
		}

	delete iCalOrganizer;
	iCalOrganizer = NULL;

	if(iSessionImpl)
		{
        // Use this entry's existing uid.
		iSessionImpl->DecrementReferenceCount();
		}
	iSessionImpl = aOther.iSessionImpl;
	if (iSessionImpl)
		{
		iSessionImpl->IncrementReferenceCount();
		}

	// ensure other entry has a full CAgnEntry
	aOther.LoadFullEntryL();
	
	// ensure other entry has summary, description and alarm action properties loaded - these
	// are stored in separate streams
	aOther.SummaryL();
	aOther.DescriptionL();
	delete aOther.AlarmL();
	
	iFullEntry->CopyFromL(*aOther.iFullEntry, aCopyType);
	iFullEntry->SetLastModifiedDate();
	iFullEntry->SetCollectionId(collectionId);
	}

void CCalEntryImpl::SetAlarmL(CCalAlarm* aAlarm)
	{
	LoadFullEntryL();
	
	if ( aAlarm == NULL ) 
		{
		// if aAlarm is NULL, clear the alarm data
		iFullEntry->ClearAlarm();
		}
	else
		{
		// This method does not take ownership of aAlarm, so need to copy the alarm details
		// before adding to the entry.
		
		// the alarm must be on the same day in local time as the event
		TDateTime dt = iFullEntry->EntryTime().LocalL().DateTime();
		TInt minutes = dt.Hour()*60 + dt.Minute();
		__ASSERT_ALWAYS(minutes - aAlarm->TimeOffset().Int() <= KAgnMinutesInADay, User::Leave(KErrNotSupported));

		iFullEntry->SetAlarmOffset(aAlarm->TimeOffset());
	 	iFullEntry->SetAlarmSoundNameL(aAlarm->AlarmSoundNameL());

		CCalContent* alarmAction = aAlarm->AlarmAction(); // doesn't take ownership
		
		if ( alarmAction )
			{
			CAgnContent* agnAlarmAction = static_cast<CAgnContent*>(alarmAction->Impl());
			
			if ( agnAlarmAction )
				{
				CAgnContent* alarmActionCopy = agnAlarmAction->CloneL();
				iFullEntry->SetAlarmAction(alarmActionCopy); // entry takes ownership of alarmActionCopy
				}					
			}
		else
		    {
		    iFullEntry->SetAlarmAction(NULL); 
		    }
		}
	}

CCalAlarm* CCalEntryImpl::AlarmL()
	{
	LoadFullEntryL();
	
	if (!iFullEntry->HasAlarm())
		{
		return NULL;
		}
        
	TTime time = iFullEntry->EntryTime().LocalL();
	
	// Invalid or non-existant entries are set on import to NULL time
	// That being the case, we return NULL for the Alarm.
	TDateTime timeOfEvent;
	if(time == Time::NullTTime())
		{
		return NULL;
		}
	else
		{
		timeOfEvent = time.DateTime();
		}

	CCalAlarm* alarm = CCalAlarm::NewL();
	CleanupStack::PushL(alarm);
	
	alarm->SetTimeOffset(iFullEntry->AlarmOffset().Int());
	alarm->SetAlarmSoundNameL(iFullEntry->AlarmSoundName());
	
	if(!iFullEntry->AlarmActionIsLoaded())
		{
		CAgnContent* agnAlarmaction = iSessionImpl->Server().RestoreAlarmActionL(iFullEntry->AlarmActionStreamId(), iSessionImpl->FileId());
		// Restore should always return something, even if it's only a Null Descriptor
		iFullEntry->SetAlarmAction(agnAlarmaction);
		}

	if (iFullEntry->AlarmAction())
		{
		CCalContent* alarmAction = CCalContent::NewL();
		CleanupStack::PushL(alarmAction);
		CAgnContent* agnAlarmActionCopy = iFullEntry->AlarmAction()->CloneL();
		alarmAction->SetImpl(agnAlarmActionCopy); // Takes ownership of agnAlarmAction.
		alarm->SetAlarmAction(alarmAction); // Takes ownership of alarmAction.
		CleanupStack::Pop(alarmAction);
		}

	CleanupStack::Pop(alarm);
	return alarm;
	}

void CCalEntryImpl::SetCommonRptDataL(const TCalRRule& aRpt, CAgnRptDef& aRptRule)
	{
	// set repeat rule data which is not specific to the rule type
	// Both repeating count and until time could be set. If so, the one come earlist will be set as repeating until time.
	// Note that the repeating until time will be adjusted in TAgnRpt::UntilTimeL() when the entry is stored (CCalEntryViewImpl::DoStore and 
	// CAgnSimpleEntry::AdjustStartUntilTimeForRepEntryL)By then, the TZ rule has been set to a repeating entry.
	aRptRule.SetInterval(aRpt.Interval());
	const_cast<TAgnRpt*> (aRptRule.RRule())->SetCount(aRpt.Count());

    TTime untilTime = aRpt.Until().TimeLocalL();
    if (untilTime != Time::NullTTime())
    	{
		TAgnCalendarTime untilTimeTAgn = CalUtils::TCalTimeToTAgnCalendarTimeL(aRpt.Until());
		aRptRule.SetUntilTime(untilTimeTAgn);
    	}
	}

void CCalEntryImpl::SetRRuleL(const TCalRRule& aRpt)
	{
	if (aRpt.Until().TimeLocalL() != Time::NullTTime() && aRpt.DtStart().TimeLocalL() >= aRpt.Until().TimeLocalL())
		{
		// if Until time is set to earlier than the start time and is non-NULL, leave
		User::Leave(KErrArgument);
		}
	LoadFullEntryL();

	//Leaves if this is a todo entry and its end date has not been set or this is a non-todo entry and its start date has not been set
	//since repeating pattern is based on those time attributes.
	if ( ! iFullEntry->EntryTime().IsSet())
		{
		User::Leave(KErrArgument);
		}

	TBool createdNewRptDef = EFalse;
	CAgnRptDef* rptDef = iFullEntry->RptDef();
	if(rptDef == NULL)
		{
		rptDef = CAgnRptDef::NewL(*iFullEntry);
		CleanupStack::PushL(rptDef);
		createdNewRptDef = ETrue;
		}

	switch (aRpt.Type())
		{
		case TCalRRule::EDaily:
			{
			TAgnDailyRpt daily(*rptDef);
			rptDef->SetRRuleL(daily);
			}
			break;
		case TCalRRule::EWeekly:
			{
			TAgnWeeklyRpt weekly(*rptDef);
			weekly.SetFirstDayOfWeek(aRpt.WkSt());
			RArray<TDay> array;
			CleanupClosePushL(array);
			aRpt.GetByDayL(array);
			const TInt KWeeklyDayCount = array.Count();
			for (TInt i = 0; i < KWeeklyDayCount; ++i)
				{
				weekly.SetDay(array[i]);
				}
			CleanupStack::PopAndDestroy(&array);
			
			rptDef->SetRRuleL(weekly);
			}
			break;
		case TCalRRule::EMonthly:
			{
			RArray<TInt> array;
			CleanupClosePushL(array);
			aRpt.GetByMonthDayL(array);
			if (array.Count() <= 0)
				{
				// may be monthly by week
				RArray<TCalRRule::TDayOfMonth> dayArray;
				CleanupClosePushL(dayArray);
				aRpt.GetByDayL(dayArray);
				const TInt KMonthlyDayCount = dayArray.Count();
				if (KMonthlyDayCount > 0)
					{
					TAgnMonthlyByDaysRpt monthlyByDayAndWeek(*rptDef);
					for (TInt i = 0; i < KMonthlyDayCount; ++i)
						{
						TCalRRule::TDayOfMonth dayOfMonth = dayArray[i];
						TAgnRpt::TWeekInMonth weekNum = CalUtils::WeekNumberToAgnWeekInMonthL(dayOfMonth.WeekInMonth());
						monthlyByDayAndWeek.SetDay(dayOfMonth.Day(), weekNum);
						}
					
					rptDef->SetRRuleL(monthlyByDayAndWeek);
					}
				CleanupStack::PopAndDestroy(&dayArray); // dayArray.Close()
				}
			else
				{
				TAgnMonthlyByDatesRpt monthlyByDate(*rptDef);
				const TInt KMonthlyDateCount = array.Count();
				for (TInt i = 0; i < KMonthlyDateCount; ++i)
					{
					monthlyByDate.SetDate(array[i]);
					}
				
				rptDef->SetRRuleL(monthlyByDate);
				}
			CleanupStack::PopAndDestroy(&array); // array.Reset();
			}
			break;
		case TCalRRule::EYearly:
			{
			RArray<TCalRRule::TDayOfMonth> dayArray;
			CleanupClosePushL(dayArray);
			aRpt.GetByDayL(dayArray);
			if (dayArray.Count() > 0)
				{
				RArray<TMonth> monthArray;
				CleanupClosePushL(monthArray);
				aRpt.GetByMonthL(monthArray);
				if (monthArray.Count() > 0)
					{
					TDay day = dayArray[0].Day();
					TAgnRpt::TWeekInMonth week = CalUtils::WeekNumberToAgnWeekInMonthL(dayArray[0].WeekInMonth());
					TMonth month = monthArray[0];

					TAgnYearlyByDayRpt yearlyByDay(*rptDef);

					// Check that the first month to repeat on is earlier than the repeat dtstart date...
					TDateTime rptStartTime = aRpt.DtStart().TimeUtcL().DateTime();
					TInt year = rptStartTime.Year();
					if (month < rptStartTime.Month())
						{
						// ...if not, start the following year
						year++;
						}
						
					TTime newStartDay = yearlyByDay.FindStartDayL(day, week, month, year);
					TCalTime newStartDaycal;
					newStartDaycal.SetTimeLocalL(newStartDay);
					const_cast<TCalRRule&>(aRpt).SetDtStart(newStartDaycal);
					TTime untilTimeLocal = yearlyByDay.UntilTimeL().LocalL();
					TDateTime rptUntilTime = untilTimeLocal.DateTime();
					if (aRpt.Count() != 0 || year < rptUntilTime.Year() ||
						(year == rptUntilTime.Year() && month < rptUntilTime.Month())
						)
						{
                        // The count has been set
                        // or the first month to repeat on is not later than the repeat until date
						rptDef->SetRRuleL(yearlyByDay);
						}
					}
				else
					{
					User::Leave(KErrArgument);	
					}	
				CleanupStack::PopAndDestroy(&monthArray);
				}
			else
				{
				TAgnYearlyByDateRpt yearlyByDate(*rptDef);
				rptDef->SetRRuleL(yearlyByDate);
				}
			CleanupStack::PopAndDestroy(&dayArray);
			}
			break;
		default:
			User::Leave(KErrNotSupported);
			break;
		}
	
	if (rptDef->RRule())
		{
		SetCommonRptDataL(aRpt, *rptDef);
		}
	
	if (createdNewRptDef)
		{
		if (rptDef->RRule())
			{
			iFullEntry->SetRptDefL(*rptDef);
			}
		CleanupStack::PopAndDestroy(rptDef);
		}
	
	//Move the entry start date is same as repeating date
	
	TDateTime newEntryDateTime;
	if(EntryTypeL() == CCalEntry::ETodo)
		{
		newEntryDateTime = EndTimeL().TimeLocalL().DateTime();	
		}
	else
		{
		newEntryDateTime = StartTimeL().TimeLocalL().DateTime();		
		}

	newEntryDateTime.SetYear(aRpt.DtStart().TimeLocalL().DateTime().Year());
	newEntryDateTime.SetMonth(aRpt.DtStart().TimeLocalL().DateTime().Month());
	newEntryDateTime.SetDay(aRpt.DtStart().TimeLocalL().DateTime().Day());
	
	//adjust the entrytime (it the entry start time for non-todos and end time for todos) 
	iFullEntry->MoveStartTimeLocalL(newEntryDateTime);
	}

void CCalEntryImpl::ClearRepeatingPropertiesL()
	{
	SimpleEntry()->ClearRepeat();
	}

TCalTime CCalEntryImpl::NextInstanceForLocalUIDL(const TCalTime& aTime)
	{
	const TTime KTimeUtc = aTime.TimeUtcL() + TTimeIntervalMicroSeconds(1);
	TTime nextTimeUtc = Time::NullTTime();
	
	const CAgnRptDef* KRptDef = SimpleEntry()->RptDef();
	if (KRptDef)
		{
		if (KRptDef->NudgeNextInstanceUtcL(KTimeUtc, nextTimeUtc) == EFalse)
			{
			nextTimeUtc = Time::NullTTime();
			}
		}
	else
		{
		TTime entryTimeUtc = SimpleEntry()->EntryTime().UtcL();
		if (KTimeUtc < entryTimeUtc)
			{
			nextTimeUtc = entryTimeUtc;
			}
		}
	
	TCalTime calTime;
	calTime.SetTimeUtcL(nextTimeUtc);
	return calTime;
	}

TCalTime CCalEntryImpl::PreviousInstanceForLocalUIDL(const TCalTime& aTime)
	{
	const TTime KTimeUtc = aTime.TimeUtcL() - TTimeIntervalMicroSeconds(1);
	TTime prevTimeUtc = Time::NullTTime();
	
	const CAgnRptDef* KRptDef = SimpleEntry()->RptDef();
	if (KRptDef)
		{
		if (KRptDef->NudgePreviousInstanceUtcL(KTimeUtc, prevTimeUtc) == EFalse)
			{
			prevTimeUtc = Time::NullTTime();
			}
		}
	else
		{
		TTime entryTimeUtc = SimpleEntry()->EntryTime().UtcL();
		if (KTimeUtc > entryTimeUtc)
			{
			prevTimeUtc = entryTimeUtc;
			}
		}
	
	TCalTime calTime;
	calTime.SetTimeUtcL(prevTimeUtc);
	return calTime;
	}
	
TCalTime CCalEntryImpl::LastModifiedDateL()
	{
	TTime lastModifiedEntry = SimpleEntry()->LastModifiedDateUtc();
	if(iSessionImpl && SimpleEntry()->RptDef() && SimpleEntry()->TimeMode()!= MAgnCalendarTimeMode::EFloating)
		{
		TTime lastModifiedTzChange = iSessionImpl->TzRulesLastModifiedDateL();
		if(lastModifiedTzChange>lastModifiedEntry)
			{
			lastModifiedEntry = lastModifiedTzChange;
			}
		}
	TCalTime lastModifiedTime;
	lastModifiedTime.SetTimeUtcL(lastModifiedEntry);
	return lastModifiedTime;
	}

TCalTime CCalEntryImpl::DTStampL()
	{
	LoadFullEntryL();
	TCalTime dTStampTime;
	dTStampTime.SetTimeUtcL(iFullEntry->DTStampUtcL());
	return dTStampTime;
	}

void CCalEntryImpl::SetLocationL(const TDesC& aLocation)
	{
	LoadFullEntryL();
	iFullEntry->SetLocationL(aLocation);
	}

const TDesC& CCalEntryImpl::LocationL()
	{
	LoadFullEntryL();
	return iFullEntry->Location();
	}

void CCalEntryImpl::SetPriorityL(TUint aPriority)
	{
	LoadFullEntryL();
	iFullEntry->SetPriority(aPriority);
	}

TUint CCalEntryImpl::PriorityL()
	{
	return SimpleEntry()->Priority();
	}

TCalTime CCalEntryImpl::StartTimeL()
	{
	return CalUtils::TAgnCalendarTimeToTCalTimeL(SimpleEntry()->StartTime());
	}

TCalTime CCalEntryImpl::EndTimeL()
	{
	TCalTime calEndTime; // initialised to Null time on construction
	if (SimpleEntry()->Type() != CCalEntry::EReminder)
		{
		calEndTime = CalUtils::TAgnCalendarTimeToTCalTimeL(SimpleEntry()->EndTime());
		}
	return calEndTime;
	}

void CCalEntryImpl::SetStartAndEndTimeL(const TCalTime& aStartTime, const TCalTime& aEndTime)
	{
	LoadFullEntryL();
	TCalTime::TTimeMode mode = aStartTime.TimeMode();
	if (aEndTime.TimeUtcL() != Time::NullTTime())
		{
		if (aStartTime.TimeUtcL() != Time::NullTTime())
			{
			// both times are non-null so check the modes
			__ASSERT_ALWAYS(aStartTime.TimeMode() == aEndTime.TimeMode(), User::Leave(KErrArgument));

			// both times are non-null so check that end time is not earlier than start time
			__ASSERT_ALWAYS(aStartTime.TimeUtcL() <= aEndTime.TimeUtcL(), User::Leave(KErrArgument));
			}
		else
			{
			// start time non-null so fetch mode from end time
			mode = aEndTime.TimeMode();
			}
		}
	__ASSERT_ALWAYS(mode == TCalTime::EFixedUtc || mode == TCalTime::EFloating, User::Leave(KErrArgument));

	// either this is a parent entry, or time mode should match recurrence ID
	__ASSERT_ALWAYS(RecurrenceIdL().TimeUtcL() == Time::NullTTime() ||
					mode == RecurrenceIdL().TimeMode(),
					User::Leave(KErrArgument));		

	TAgnCalendarTime agnStartTime = CalUtils::TCalTimeToTAgnCalendarTimeL(aStartTime);
	TAgnCalendarTime agnEndTime = CalUtils::TCalTimeToTAgnCalendarTimeL(aEndTime);

	const CCalEntry::TType KType = SimpleEntry()->Type();
		
	switch (KType)
		{
		case CCalEntry::ETodo:
			// for todos, if end time is not set, set start time to null as well - this is an undated entry
			if ( ! agnEndTime.IsSet())
				{
				agnStartTime = agnEndTime;
				}
			break;
		case CCalEntry::EReminder:
			// for reminders, end time is the same as start time
			agnEndTime = agnStartTime;
			break;
		case CCalEntry::EAppt:
		case CCalEntry::EAnniv:
		case CCalEntry::EEvent:
			// for other entries, if end time is not set, make it the same as the start time
			if ( ! agnEndTime.IsSet())
				{
				agnEndTime = agnStartTime;
				}
			break;
		default:
			// bad entry type
			User::Leave(KErrArgument);
			break;
		}
		
	iFullEntry->SetStartAndEndTimeL(agnStartTime, agnEndTime);
	}

MAgnCalendarTimeMode::TTimeMode CCalEntryImpl::TimeMode() const
	{
	return SimpleEntry()->TimeMode();
	}

TCalTime CCalEntryImpl::CompletedTimeL()
	{
	TTime completedDateUtc(Time::NullTTime());
	if (SimpleEntry()->Type() == CCalEntry::ETodo)
		{
		completedDateUtc = SimpleEntry()->CompletedDateUtc();
		}
	TCalTime calCompletedDate;
	calCompletedDate.SetTimeUtcL(completedDateUtc);
	return calCompletedDate;
	}

void CCalEntryImpl::SetCompletedL(TBool aCompleted, const TCalTime& aDate)
	{
	LoadFullEntryL();
	if (SimpleEntry()->Type() == CCalEntry::ETodo)
		{
		if (aCompleted)
			{
			SimpleEntry()->SetCompletedDateUtcL(aDate.TimeUtcL());
			SetStatusL(CCalEntry::ETodoCompleted);
			}
		else
			{
			SimpleEntry()->SetIncomplete(); // resets completed date to null time
			SetStatusL(CCalEntry::ETodoNeedsAction);
			}
		}
	else
		{
		User::Leave(KErrNotSupported);
		}
	}

void CCalEntryImpl::SetSummaryL(const TDesC& aSummary)
	{
	LoadFullEntryL();
	HBufC* summ = aSummary.AllocL();
	iFullEntry->SetSummary(summ); // takes ownership of aSummary
	}

const TDesC& CCalEntryImpl::SummaryL()
	{
	LoadFullEntryL();

	if(!iFullEntry->SummaryIsLoaded())
		{
		__ASSERT_DEBUG(iFullEntry->SummaryStreamId() != KNullStreamId, Panic(EAgmNoNotesStreamId));
		HBufC* summary = iSessionImpl->Server().RestoreTextL(iFullEntry->SummaryStreamId(), iSessionImpl->FileId());
		// Restore should always return something, even if it's only a Null Descriptor
		iFullEntry->SetSummary(summary);
		}

	return iFullEntry->Summary();
	}

void CCalEntryImpl::SetDescriptionL(const TDesC& aDescription)
	{
	LoadFullEntryL();
	HBufC* desc = aDescription.AllocL();
	iFullEntry->SetDescription(desc); // takes ownership of aDescription
	}

const TDesC& CCalEntryImpl::DescriptionL()
	{
	LoadFullEntryL();
	
	if(!iFullEntry->DescriptionIsLoaded())
		{
		__ASSERT_DEBUG(iFullEntry->DescriptionStreamId() != KNullStreamId, Panic(EAgmNoNotesStreamId));
		HBufC* description = iSessionImpl->Server().RestoreTextL(iFullEntry->DescriptionStreamId(), iSessionImpl->FileId());
		// Restore should always return something, even if it's only a Null Descriptor
		iFullEntry->SetDescription(description);
		}

	return iFullEntry->Description();
	}

CCalEntry::TType CCalEntryImpl::EntryTypeL()
	{
	return SimpleEntry()->Type();
	}

void CCalEntryImpl::SetStatusL(CCalEntry::TStatus aStatus)
	{
	LoadFullEntryL();
	switch (aStatus)
		{
		case CCalEntry::ETentative:
		case CCalEntry::EConfirmed:
			__ASSERT_ALWAYS(EntryTypeL() != CCalEntry::ETodo, User::Leave(KErrNotSupported));
			break;
		case CCalEntry::ECancelled:
			SimpleEntry()->SetIncomplete();
			break;
		
		case CCalEntry::ETodoCompleted:
		case CCalEntry::ETodoNeedsAction:
		case CCalEntry::ETodoInProcess:
			__ASSERT_ALWAYS(EntryTypeL() == CCalEntry::ETodo, User::Leave(KErrNotSupported));
			break;
		default:
			// do nothing
			break;
		}
	if (aStatus == CCalEntry::ETodoCompleted)
		{
		if (iFullEntry->CompletedDateUtc() == Time::NullTTime())
			{
			TTime time;
			time.UniversalTime();
			iFullEntry->SetCompletedDateUtcL(time);
			}
		}
	
	iFullEntry->SetStatus(aStatus);
	}

void CCalEntryImpl::SetReplicationStatusL(CCalEntry::TReplicationStatus aReplicationStatus)
	{
	LoadFullEntryL();
	iFullEntry->SetReplicationStatusL(aReplicationStatus);
	}

CCalEntry::TReplicationStatus CCalEntryImpl::ReplicationStatusL()
	{
	LoadFullEntryL();
	return iFullEntry->ReplicationStatus();
	}

CCalEntry::TStatus CCalEntryImpl::StatusL()
	{
	return SimpleEntry()->Status();
	}

void CCalEntryImpl::SetSequenceNumberL(TInt aSeqNum)
	{
	LoadFullEntryL();
	iFullEntry->SetSequenceNumber(aSeqNum);
	}

void CCalEntryImpl::SetLastModifiedDateL()
	{
	LoadFullEntryL();
	iFullEntry->SetLastModifiedDate();
	}
	
void CCalEntryImpl::SetLastModifiedDateL(const TCalTime& aModifiedTime)
	{
	LoadFullEntryL();
	iFullEntry->SetLastModifiedDateUtc(aModifiedTime.TimeUtcL());
	}
	
void CCalEntryImpl::SetDTStampL(const TCalTime& aDTStampTime)
	{
	LoadFullEntryL();
	iFullEntry->SetDTStampUtcL(aDTStampTime.TimeUtcL());
	}

TAgnEntryId CCalEntryImpl::AgnEntryIdL()
	{
	return SimpleEntry()->EntryId();
	}

void CCalEntryImpl::SetLocalUidL(TCalLocalUid aLocalId)
	{
	LoadFullEntryL();
	iFullEntry->SetLocalUid(aLocalId);
	}

TCalLocalUid CCalEntryImpl::LocalUidL()
	{
	if(iLiteEntry)
		{
		return iLiteEntry->LiteEntry().LocalUid();
		}
	else
		{
		return iFullEntry->LocalUid();
		}
	}

TUint8 CCalEntryImpl::ShortFileIdL()
	{
	if(iLiteEntry)
		{
		return iLiteEntry->LiteEntry().CollectionId();
		}
	else
		{
		return iFullEntry->CollectionId();
		}	
	}

CCalEntry::TTransp CCalEntryImpl::BusyStatusL()
	{
	LoadFullEntryL();
	return iFullEntry->BusyStatus();
	}

void CCalEntryImpl::SetBusyStatusL(CCalEntry::TTransp aBusyStatus)
	{
	LoadFullEntryL();
	iFullEntry->SetBusyStatusL(aBusyStatus);
	}

CCalGeoValue* CCalEntryImpl::GeoValueL()
	{
	LoadFullEntryL();
	TReal geoLatitude;
	TReal geoLongitude;
	iFullEntry->GeoValue(geoLatitude,geoLongitude);
	if(geoLatitude != KGEODefaultValue && geoLongitude != KGEODefaultValue)
		{
		CCalGeoValue* geoValue = CCalGeoValue::NewL();
		CleanupStack::PushL(geoValue);
		geoValue->SetLatLongL(geoLatitude,geoLongitude);
		CleanupStack::Pop(geoValue);
		return geoValue;
		}
	return NULL;		
	}

void CCalEntryImpl::SetGeoValueL(const CCalGeoValue& aGeoValue)
	{
	LoadFullEntryL();
	TReal geoLatitude;
	TReal geoLongitude;
	aGeoValue.GetLatLong(geoLatitude,geoLongitude);
	iFullEntry->SetGeoValueL(geoLatitude,geoLongitude);
	}

void CCalEntryImpl::ClearGeoValueL()
	{
	LoadFullEntryL();
	iFullEntry->SetGeoValueL(KGEODefaultValue,KGEODefaultValue);
	}
	
TCalTime CCalEntryImpl::FindRptUntilTimeL(TInt aCount)
	{
	const CAgnRptDef* KRptDef = SimpleEntry()->RptDef();
	
	TTime untilTime = Time::NullTTime();
	
	if (KRptDef)
		{
		untilTime = KRptDef->RRule()->FindRptUntilTimeLocalL(aCount);
		}
	
	TCalTime calUntilTime;
	calUntilTime.SetTimeLocalL(untilTime);
	
	return calUntilTime;
	}


  void CCalEntryImpl::AddAttachmentL(CCalAttachment* aAttachment)
   	{
   	__ASSERT_ALWAYS(aAttachment, User::Leave(KErrArgument));
   	
	PopulateAttachmentListL();
	iCalAttachmentList->AppendL(aAttachment);
	
	TRAPD(err , iFullEntry->AddAttachmentL(&aAttachment->Impl()));
 
	if (err != KErrNone)
 		{
		TInt count = iCalAttachmentList->Count();
 		iCalAttachmentList->Remove(count - 1);
 		User::Leave(err);
 		}
 		
   	aAttachment->Impl().ClearFlag(CAgnAttachment::EOwnedByCalAttachment);

   	}

void CCalEntryImpl::PopulateAttachmentListL()
	{
   	if (!iCalAttachmentList)
   		{

		LoadFullEntryL();
		iCalAttachmentList = new (ELeave) RPointerArray<CCalAttachment>(KAttachmentGranularity);

		const TInt KAttachmentCount = iFullEntry->AttachmentCount();
		for (TInt i = 0; i < KAttachmentCount; ++i)
			{
			CAgnAttachment& agnAttachment = iFullEntry->Attachment(i);
			CCalAttachment* calAttachment = CCalAttachment::NewL(agnAttachment, *iSessionImpl);
			CleanupStack::PushL(calAttachment);
			agnAttachment.ClearFlag(CAgnAttachment::EOwnedByCalAttachment);
			iCalAttachmentList->AppendL(calAttachment);
			CleanupStack::Pop(calAttachment);
			}
   		}

   	}	
	
void CCalEntryImpl::DeleteAttachmentL(const CCalAttachment& aAttachment)
	{
	LoadFullEntryL();
	TInt index = iFullEntry->DeleteAttachmentL(aAttachment.Impl());
	if(iCalAttachmentList && index >= 0 && index < iCalAttachmentList->Count())
		{
		delete (*iCalAttachmentList)[index];
		iCalAttachmentList->Remove(index);
		__ASSERT_DEBUG(iCalAttachmentList->Count() == iFullEntry->AttachmentCount(), Panic(EAgmErrAttachmentCountCorrupt)); 
		}
	}
	
CCalAttachment* CCalEntryImpl::AttachmentL(TInt aIndex)
	{
	PopulateAttachmentListL();

	if (aIndex < 0 || aIndex >= iCalAttachmentList->Count() )
		{
		return NULL;
		}
		
	return (*iCalAttachmentList)[aIndex];
	}

TInt CCalEntryImpl::AttachmentCountL()
	{
	LoadFullEntryL();
	return iFullEntry->AttachmentCount();
	}
	
CAgnSimpleEntry* CCalEntryImpl::SimpleEntry()
	{
	if (!iFullEntry)
		{
		return &iLiteEntry->LiteEntry();
		}
	return iFullEntry;
	}

const CAgnSimpleEntry* CCalEntryImpl::SimpleEntry() const
	{
	if (!iFullEntry)
		{
		return &iLiteEntry->LiteEntry();
		}
	return iFullEntry;
	}

void CCalEntryImpl::SetUserIntL( TUint32 aUserInt )
    {
    SimpleEntry()->SetUserInt(aUserInt);
    }

TUint32 CCalEntryImpl::UserIntL()
    {
    return SimpleEntry()->UserInt();
    }


//  CCalEntryIdImpl //

CCalEntryIdImpl* CCalEntryIdImpl::NewL(TDesC8* aFlatData)
	{
	CCalEntryIdImpl* self = new(ELeave) CCalEntryIdImpl();
	CleanupStack::PushL(self);
	self->ConstructL(aFlatData);
	CleanupStack::Pop(self);
	return self;
	}

CCalEntryIdImpl::CCalEntryIdImpl()
	{
	}

CCalEntryIdImpl::~CCalEntryIdImpl()
	{
	delete iFlatData;
	}

void CCalEntryIdImpl::ConstructL(TDesC8* aFlatData)
	{
	__ASSERT_ALWAYS(aFlatData != NULL, User::Leave(KErrArgument));
	
	iFlatData = aFlatData;
	iUniqueId = reinterpret_cast<const TAgnAlarmInfo*>(aFlatData->Ptr());
	}

TPtrC8 CCalEntryIdImpl::IdL()
	{
	return iUniqueId->iGlobalIdentifier;
	}

TPtrC CCalEntryIdImpl::StoreFileNameL()
	{
	return iUniqueId->iFileName;
	}

TCalTime CCalEntryIdImpl::RecurrenceIdL()
	{
	TCalTime time;
	
	if(iUniqueId->iTimeMode ==MAgnCalendarTimeMode::EFloating)
 		{
 		time.SetTimeLocalFloatingL(iUniqueId->iRecurrenceId);
 		}
 	else
 		{
 		time.SetTimeUtcL(iUniqueId->iRecurrenceId);
 		}
 	
 	return time;
	}

TCalTime CCalEntryIdImpl::InstanceTimeL()
	{
	TCalTime time;

	if(iUniqueId->iTimeMode == MAgnCalendarTimeMode::EFloating)
		{
		time.SetTimeLocalL(iUniqueId->iInstanceTime);
		}
	else
		{
		time.SetTimeUtcL(iUniqueId->iInstanceTime);		
		}
		
	return time;
	}

TCalLocalUid CCalEntryIdImpl::LocalUidL()
	{
	return iUniqueId->iAgnUniqueId;
	}
	

/** Construct a new CCalLiteEntry 

@param aLiteEntry The TAgnLiteEntry to be shared between CCalEntry objects.
@param aSession A reference to the CCalSession
@internalComponent
*/
CCalLiteEntry* CCalLiteEntry::NewL(CAgnSimpleEntry& aSimpleEntry, RAgendaServ& aAgendaServ)
	{
	CCalLiteEntry* self = new(ELeave) CCalLiteEntry(aSimpleEntry, aAgendaServ);
	return self;
	}

/** Constructor

@param aLiteEntry The TAgnLiteEntry to be shared between CCalEntry objects.
@param aSession A reference to the CCalSession
@internalComponent
*/	
CCalLiteEntry::CCalLiteEntry(CAgnSimpleEntry& aLiteEntry, RAgendaServ& aAgendaServ)
	: iAgendaServ(aAgendaServ), iLiteEntry(aLiteEntry)
	{
	iAgendaServ.IncreaseRef();
	}

/** Deletes the TAgnLiteEntry that is contained 

@internalComponent
*/	
CCalLiteEntry::~CCalLiteEntry()
	{
	iAgendaServ.DeleteSimpleEntry(&iLiteEntry);
	iAgendaServ.DecreaseRef();
	}
	
/** Get a reference to the TAgnLiteEntry

@return A reference to the TAgnLiteEntry
@internalComponent
*/
CAgnSimpleEntry& CCalLiteEntry::LiteEntry() const
	{
	return iLiteEntry;
	}

/** Increments the reference count

This should only be called by a CCalEntry object that is being created from a CCalLiteEntry 
@internalComponent
*/	
void CCalLiteEntry::IncrementRefCount()
	{
	++iRefCount;
	}

/** Decrements the reference count and deletes this CCalLiteEntry if there are no more entries refering to it

This should only be called by a CCalEntry object
@internalComponent
*/	
void CCalLiteEntry::DecrementRefCount()
	{
	__ASSERT_ALWAYS(iRefCount > 0, User::Invariant());
	if (--iRefCount == 0)
		{
		delete this;
		}
	}
