/*
* Copyright (c) 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: This file implements class CMessageIterator.
*
*/
#include "emailmessage.h"
#include "messageiterator.h"
#include "emailapiutils.h"
#include "cfsmailplugin.h"
#include "emailapiutils.h"
#include "emailclientapi.hrh"
#include "mfsmailiterator.h"
// number of messages in chunk to retrive from protocol plugin. Actual chunk
// size is one less because last element is used for reference to next chunk
// retrieval. See ReadNextChunkL() for details.
const TInt KMessageChunkSize = 5;
const TInt KUndefined = -1;
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CMessageIterator* CMessageIterator::NewL(
MFSMailIterator* aIterator,
CPluginData& aPluginData,
TUint aCount )
{
CMessageIterator* iter = new ( ELeave )
CMessageIterator( aIterator, aPluginData, aCount );
return iter;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CMessageIterator::~CMessageIterator()
{
iPluginData.ReleaseInstance();
TInt count = iMessageArray.Count();
iMessageArray.ResetAndDestroy();
for (TInt i = count; i < iFsMessageArray.Count(); i++)
{
delete iFsMessageArray[i];
}
iFsMessageArray.Reset();
delete iIterator;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TEmailTypeId CMessageIterator::InterfaceId() const
{
return KEmailIFUidMessageIterator;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CMessageIterator::Release()
{
delete this;
}
// -----------------------------------------------------------------------------
// Returns next message
// Messages are retrieved from protocol plugin in chunks of x messages and
// when NextL has be called for x times, next chunk is retrieved. This
// is trade-off between RAM consumption and speed.
// -----------------------------------------------------------------------------
MEmailMessage* CMessageIterator::NextL()
{
if ( iCursor == KUndefined )
{
// Buffer empty, read the first chunk
if ( !ReadNextChunkL() )
{
// No messages found,
// Reset the cursor and return NULL
iCursor = KUndefined;
iStartMsgId = TFSMailMsgId();
return NULL;
}
// Items found, return the first item in the buffer
iCursor = 0;
}
else
{
// Iterate to the next item
iCursor++;
}
return ReadFromChunkL();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
MEmailMessage* CMessageIterator::PreviousL()
{
if ( iCursor == KUndefined )
{
iStartMsgId = TFSMailMsgId();
// Buffer empty, client should first call NextL
return NULL;
}
// Iterate to the previous item
iCursor--;
return ReadFromChunkL();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TBool CMessageIterator::ReadNextChunkL( )
{
TBool chunkFound = EFalse;
// Delete previous items if exist
CleanCache();
iHasMoreNextItems = iIterator->NextL(
iStartMsgId,
KMessageChunkSize,
iFsMessageArray );
if ( iFsMessageArray.Count() > 0)
{
chunkFound = ETrue;
// Set the cursor to the first item
iCursor = 0;
iHasMorePrevItems = ETrue;
}
return chunkFound;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TBool CMessageIterator::ReadPreviousChunkL( )
{
TBool chunkFound = EFalse;
// Delete previous items if exist
CleanCache();
RPointerArray<CFSMailMessage> tmp;
iHasMorePrevItems = iIterator->PreviousL(
iStartMsgId,
KMessageChunkSize,
tmp );
TInt count = tmp.Count();
if ( count > 0)
{
// It seems that items have been found
// Set the cursor to the end of array
iCursor = count - 1;
iHasMoreNextItems = ETrue;
chunkFound = ETrue;
// Revise the order of the buffer.
// Create complete cache, so it is easier to iterate,
// as now we have to start from the end of cache
for (TInt i = count; i > 0; i--)
{
CFSMailMessage* msg = tmp[i-1];
iFsMessageArray.AppendL( msg );
AddToCacheL( msg );
}
}
return chunkFound;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
MEmailMessage* CMessageIterator::ReadFromChunkL()
{
if ( iCursor >= KMessageChunkSize )
{
if ( iHasMoreNextItems )
{
iStartMsgId = iFsMessageArray[iCursor-1]->GetMessageId();
if ( !ReadNextChunkL() )
{
// No more items found,
// set the cursor to the previous item,
// and return NULL.
iCursor--;
return NULL;
}
}
else
{
// No more items found,
// set the cursor to the previous item,
// and return NULL.
iCursor--;
return NULL;
}
}
else if ( iCursor < 0 )
{
iStartMsgId = iFsMessageArray[0]->GetMessageId();
if ( iHasMorePrevItems )
{
if ( !ReadPreviousChunkL() )
{
// Buffer is empty now, client should call nextL,
// and start reading from the start of the buffer
iCursor = KUndefined;
return NULL;
}
}
else
{
// Buffer is empty now, client should call nextL,
// and start reading from the start of the buffer
iCursor = KUndefined;
return NULL;
}
}
if ( iCursor < iFsMessageArray.Count() )
{
/* There are items to read in the cache */
if ( iCursor >= iMessageArray.Count() )
{
AddToCacheL( iFsMessageArray[iCursor] );
}
return iMessageArray[iCursor];
}
else
{
// No more items found,
// set the cursor to the previous item,
// and return NULL.
iCursor--;
return NULL;
}
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CMessageIterator::AddToCacheL( CFSMailMessage* aFsMsg )
{
CEmailMessage* message = CEmailMessage::NewL( iPluginData, aFsMsg, EAPIOwns );
iMessageArray.AppendL(message);
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CMessageIterator::CleanCache()
{
// This is strange loop indeed
// Both arrays has items that are deleted, iMessageArray has objects that point to iFsMessageArray
// Index in both arrays goes syncronously
// To prevent double destruction, first delete iMessageArray onjects and then the rest of the iFsMessageArray
TInt count = iMessageArray.Count();
iMessageArray.ResetAndDestroy();
for (TInt i = count; i < iFsMessageArray.Count(); i++)
{
iFsMessageArray.Remove(count);
}
iFsMessageArray.Reset();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
TUint CMessageIterator::Count() const
{
return iCount;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void CMessageIterator::ConstructL()
{
iPlugin = iPluginData.ClaimInstanceL();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
CMessageIterator::CMessageIterator(
MFSMailIterator* aIterator,
CPluginData& aPluginData,
TUint aCount ) :
iIterator( aIterator ),
iPluginData( aPluginData ),
iStartMsgId( TFSMailMsgId() ),
iState( EReadNextMessageChunk ),
iFsMessageArray( KMessageChunkSize ),
iCount( aCount ),
iCursor ( KUndefined ),
iFirstMsgId( TFSMailMsgId() ),
iHasMoreNextItems( ETrue ),
iHasMorePrevItems( ETrue )
{
}
// End of file.