// Copyright (c) 2007-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:
// CIMPLAINBODYTEXT.CPP
//

#include "MIUTMSG.H"
#include "MIUTCONV.H"
#include "MIUT_ERR.H"
#include "CIMPLAINBODYTEXT.H"
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 
#include "cimmessagepart.h" 
#include "cimconvertcharconv.h"
#include "miut_errconsts.h"
#endif
#include <cmsvplainbodytext.h>

/**
NewL Factory method.
@param	aEmailMessage.   The CImEmailMessage refernce corresponding to the message whose body text is being processed.
@param	aMsvEntry.		 The CMsvEntry correspoding to the message being processed.
@param  aEntryType.		 The TImEmailEntryType for the message.
@param	aChunkLength.	 The length of the chunk that will be stored/restored in a single operation.
@param  aWriteMode.		 Indicates whether CMsvStore needs to be opened in Read/Write mode.
						 ETrue indicates Write mode.
						 EFalse indicates Read mode.
@return CImPlainBodyText.Pointer to CImPlainBodyText.
*/	
CImPlainBodyText* CImPlainBodyText::NewL(CImEmailMessage& aEmailMessage, CMsvEntry& aMsvEntry, CImEmailMessage::TImEmailEntryType aEntryType, TInt aChunkLength, TBool aWriteMode)
	{
	CImPlainBodyText* self = new (ELeave) CImPlainBodyText(aEmailMessage, aMsvEntry);
	CleanupStack::PushL(self);
	self->ConstructL(aChunkLength, aEntryType, aWriteMode);
	CleanupStack::Pop();
	return self;
	}

/**
Constructor
@param	aEmailMessage. The CImEmailMessage refernce corresponding to the message whose body text is 
@param	aMsvEntry.	   The CMsvEntry correspoding to the message being processed.
@return None.
*/
CImPlainBodyText::CImPlainBodyText(CImEmailMessage& aEmailMessage, CMsvEntry& aMsvEntry)
: CMsgActive(EPriorityNormal), iEmailMessage(aEmailMessage), iMsvEntry(aMsvEntry)
	{
	}

/**
The 2nd Phase construction.
*/	
void CImPlainBodyText::ConstructL(TInt aChunkLength, CImEmailMessage::TImEmailEntryType aEntryType, TBool aWriteMode)
	{
	iMessageId = iMsvEntry.EntryId();
	RArray<TMsvId> textIdArray;
	CleanupClosePushL (textIdArray);
	iEmailMessage.GetBodyTextEntryIdL(iMessageId, aEntryType);	
	
	// A message may contain more than one text part.
	TInt count = iEmailMessage.Selection().Count();
	for(TInt i=0;i<count;++i)
		{
		textIdArray.Append(iEmailMessage.Selection().At(i));
		}
		
	TUint charset = 0; // Will contain the charset when GetCharacterSetL returns.
	TBool override = EFalse; // Will be set to ETrue if the existing charset was overidden.
	iEmailMessage.GetCharacterSetL(iMessageId,charset,override);	
	
	if(aWriteMode)
		{
		RFs& fileSvrSession = iMsvEntry.Session().FileSession();
		
		CCnvCharacterSetConverter* characterConverter = CCnvCharacterSetConverter::NewL();
		CleanupStack::PushL(characterConverter);
		
		CImConvertCharconv* charConv = CImConvertCharconv::NewL(*characterConverter, fileSvrSession);
		CleanupStack::PushL(charConv);
		
		TUint defaultCharset = charConv->DefaultCharset();
		CleanupStack::PopAndDestroy(2,characterConverter); // charConv, characterConverter
		
		iMsvEntry.SetEntryL(textIdArray[0]);
		iStore = iMsvEntry.EditStoreL();
		// Body text is stored in MailStore as 16 bit so set iIs8Bit to EFalse.
		iPlainTextArray.Append(iStore->InitialisePlainBodyTextForWriteL(EFalse, charset, defaultCharset));	
		}	
	else
		{
		TInt textIdCount = textIdArray.Count();
		for(TInt i=0; i<textIdCount; ++i)
			{
			// Pointing to the text entry.
			iMsvEntry.SetEntryL(textIdArray[i]);	
			CMsvStore* store = iMsvEntry.ReadStoreL();
			CleanupStack::PushL(store);
			
			iPlainTextArray.Append( store->InitialisePlainBodyTextForReadL(aChunkLength));
			// if the existing charset was overidden by calling CImEmailMessage::SetCharacterSetL
			if(override)
				{
				iPlainTextArray[i]->SetCharacterSetL(charset);
				}
			CleanupStack::PopAndDestroy(store);
			store = NULL;
			}
		}
	CleanupStack::PopAndDestroy(&textIdArray);
	CActiveScheduler::Add(this);
	}

/**
Destructor
*/
EXPORT_C CImPlainBodyText::~CImPlainBodyText()
	{
	delete iStoreMessagePart;
	iPlainTextArray.ResetAndDestroy();
	iPlainTextArray.Close();	
	delete iStore;
	}

/**
Store the plain body text part in chunks.
@param aChunk. 				The 8 bit chunk that is to be stored.
@param aStatus. 			The TRequestStatus parameter for this request.
@leave KErrAccessDenied.	If CMsvStore was opened in Read mode or
							If CommitL is already called.
@leave Other 				Standard system-wide error codes.
@return void.
*/
EXPORT_C void CImPlainBodyText::StoreChunkL(const TDesC8& aChunk, TRequestStatus& aStatus)
	{
	iPlainTextArray[0]->StoreChunkL(aChunk, aStatus);
	}


/**
Store the plain body text part in chunks,synchronous version.
@param aChunk. 				The 8 bit chunk that is to be stored.
@leave KErrAccessDenied.	If CMsvStore was opened in Read mode or
							If CommitL is already called.
@leave Other 				Standard system-wide error codes.
@return void.
*/
EXPORT_C void CImPlainBodyText::StoreChunkL(const TDesC8& aChunk)
	{
	iPlainTextArray[0]->StoreChunkL(aChunk);
	}

/**
Store the body part in chunks(16 bit version).
@param aChunk 			 The 16 bit chunk that is to be stored.
@param aStatus	 		 The TRequestStatus parameter for this request.
@leave KErrNotSupported  If the 8-bit storage was enabled.
@leave KErrAccessDenied  If CMsvStore was opened in Read mode or
						 IfCommitL is already called.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::StoreChunkL(const TDesC16& aChunk, TRequestStatus& aStatus)
	{
	iPlainTextArray[0]->StoreChunkL(aChunk, aStatus);
	}

/**
Store the body part in chunks(16 bit synchronous version).
@param aChunk 			 The 16 bit chunk that is to be stored.
@leave KErrNotSupported  If the 8-bit storage was enabled.						 
@leave KErrAccessDenied  If CMsvStore was opened in Read mode or
						 If CommitL is already called.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::StoreChunkL(const TDesC16& aChunk)
	{
	iPlainTextArray[0]->StoreChunkL(aChunk);
	}
	


/**
Converts and stores the CRichText contents to a plain text.
@param aRichText 		 The CRichText object that will be stored as plain body text.
@leave KErrNotSupported  If the 8-bit storage was enabled.
@leave KErrAccessDenied  If CMsvStore was opened in Read mode or
						 If CommitL is already called.
@leave Other 			 Standard system-wide error codes.
@return void.
*/
EXPORT_C void CImPlainBodyText::StoreRichTextAsPlainTextL(CRichText& aRichText)
	{
	iPlainTextArray[0]->StoreRichTextAsPlainTextL(aRichText);
	}

/**
Retrieve the next chunk of the plain body text.
@param aChunk 			 The output parameter contains the requested chunk.
@param aStatus.			 The TRequestStatus for this request.
@leave KErrAccessDenied  If CMsvStore was opened in Write mode.
@leave KErrNotSupported  If 16-bit storage is enabled.
@leave KErrUnderflow 	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 				Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::NextChunkL(TDes8& aChunk, TRequestStatus& aStatus)
	{
	__ASSERT_DEBUG(iChunkRetrievalState == EIdleState, gPanic(EImcmNonIdleRetrievalState));
	iChunkRetrievalState = ENextChunk8Bit;
	
	iChunk8 = &aChunk;
	iChunk16 = NULL;	
	iPlainTextArray[iIndex]->NextChunkL(aChunk, iStatus);
	SetActive();
	Queue(aStatus);
	}

/**
Retrieve the next chunk of the plain body text.
@param aChunk 			 The output parameter contains the requested chunk.
@leave KErrNotSupported  If CMsvStore was opened in Write mode.
@leave KErrNotSupported  If 16-bit storage is enabled.
@leave KErrUnderflow	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::NextChunkL(TDes8& aChunk)
	{
	iPlainTextArray[iIndex]->NextChunkL(aChunk);
	// If there is more than one text part for the message move to next text part.
	if(aChunk.Length() == 0 && iIndex + 1 < iPlainTextArray.Count())
		{
		iPlainTextArray[++iIndex]->NextChunkL(aChunk);
		}
	}



/**
Restore the plain body text into chunks.
@param aChunk  			The output parameter contains the requested chunk on completion.
@param aStatus 			The TRequestStatus parameter for this request.
@leave KErrNotSupported If CMsvStore was opened in Write mode.
@leave KErrUnderflow	If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::NextChunkL(TDes16& aChunk, TRequestStatus& aStatus)
	{
	__ASSERT_DEBUG(iChunkRetrievalState == EIdleState, gPanic(EImcmNonIdleRetrievalState));
	iChunkRetrievalState = ENextChunk16Bit;
			
	iChunk16 = &aChunk;
	iChunk8 = NULL;
	iPlainTextArray[iIndex]->NextChunkL(aChunk, iStatus);
	SetActive();
	Queue(aStatus);
	}

/**
Restores the plain body text into chunks.
@param aChunk  			 The output parameter contains the requested chunk on completion.
@leave KErrNotSupported  If CMsvStore was opened in Write mode.
@leave KErrUnderflow	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::NextChunkL(TDes16& aChunk)
	{
	iPlainTextArray[iIndex]->NextChunkL(aChunk);
	// If there is more than one text part for the message move to next text part.
	if(aChunk.Length() == 0 && iIndex + 1 < iPlainTextArray.Count())
		{
		iPlainTextArray[++iIndex]->NextChunkL(aChunk);
		}
	}

/**
Retrieve the next chunk of the plain body text.
@param aChunk 			 The output parameter contains the requested chunk.
@leave KErrNotSupported  If CMsvStore was opened in Write mode.
@leave KErrNotSupported  If 16-bit storage is enabled.
@leave KErrUnderflow	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::PreviousChunkL(TDes8& aChunk, TRequestStatus& aStatus)
	{
	__ASSERT_DEBUG(iChunkRetrievalState == EIdleState, gPanic(EImcmNonIdleRetrievalState));
	iChunkRetrievalState = EPreviousChunk8Bit;
	
	iChunk8 = &aChunk;
	iChunk16 = NULL;	
	iPlainTextArray[iIndex]->PreviousChunkL(aChunk, iStatus);
	SetActive();
	Queue(aStatus);
	}


/**
Retrieve the next chunk of the plain body text.
@param aChunk 			 The output parameter contains the requested chunk.
@leave KErrNotSupported  If CMsvStore was opened in Write mode.
@leave KErrNotSupported  If 16-bit storage is enabled.
@leave KErrUnderflow	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::PreviousChunkL(TDes8& aChunk)
	{
	iPlainTextArray[iIndex]->PreviousChunkL(aChunk);
	// If message had more than one text part move to previous text part.
	if(aChunk.Length() == 0 && iIndex - 1 >= 0)
		{
		iPlainTextArray[--iIndex]->PreviousChunkL(aChunk);
		}
	}	

/**
Restore the plain body text into chunks.
@param aChunk            The output parameter contains the requested chunk on completion.
@param aStatus	         The TRequestStatus parameter for this request.
@leave KErrNotSupported  If CMsvStore was opened in Write mode.
@leave KErrUnderflow	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::PreviousChunkL(TDes16& aChunk, TRequestStatus& aStatus)
	{
	__ASSERT_DEBUG(iChunkRetrievalState == EIdleState, gPanic(EImcmNonIdleRetrievalState));
	iChunkRetrievalState = EPreviousChunk16Bit;
	
	iChunk16 = &aChunk;
	iChunk8 = NULL;
	iPlainTextArray[iIndex]->PreviousChunkL(aChunk, iStatus);
	SetActive();
	Queue(aStatus);
	}

/**
Restore the plain body text into chunks.
@param aChunk            The output parameter contains the requested chunk on completion.
@leave KErrNotSupported  If CMsvStore was opened in Write mode.
@leave KErrUnderflow	 If aChunk MaxLength is less than iChunkMaxLength.
@leave Other 			 Standard system-wide error codes.
@return void
*/
EXPORT_C void CImPlainBodyText::PreviousChunkL(TDes16& aChunk)
	{
	iPlainTextArray[iIndex]->PreviousChunkL(aChunk);
	// If message had more than one text part move to previous text part.
	if(aChunk.Length() == 0 && iIndex - 1 >= 0)
		{
		iPlainTextArray[--iIndex]->PreviousChunkL(aChunk);
		}
	}	



void CImPlainBodyText::DoRunL()
	{
	__ASSERT_DEBUG(iChunkRetrievalState != EIdleState, gPanic(EImcmIdleRetrievalState));
	
	TBool callComplete = ETrue;
	switch(iChunkRetrievalState)
		{
		// DoRunL is called as a result to a call to 8-bit asynchronous NextChunkL.
		case ENextChunk8Bit:
			{ 
			// Check if there are more than one body text part.
			if(iChunk8->Length() == 0 && iIndex + 1 < iPlainTextArray.Count())
				{
				iPlainTextArray[++iIndex]->NextChunkL(*iChunk8, iStatus);
				SetActive();
				callComplete = EFalse;
				}
			break;
			}
		case ENextChunk16Bit:
			{
			// Check if there are more than one body text part
			if(iChunk16->Length() == 0 && iIndex + 1 < iPlainTextArray.Count())
				{
				iPlainTextArray[iIndex]->NextChunkL(*iChunk16, iStatus);
				SetActive();
				callComplete = EFalse;
				}
			break;	
			}
	
		case EPreviousChunk8Bit:
			{
			// DoRunL is called as a result to a call to 8-bit asynchronous PreviousChunkL.
			if(iChunk8->Length() == 0 && iIndex - 1 >= 0)
				{
				iPlainTextArray[--iIndex]->NextChunkL(*iChunk8, iStatus);
				SetActive();
				callComplete = EFalse;
				}
			break;	
			}
		case EPreviousChunk16Bit:
			{
			if(iChunk16->Length() == 0 && iIndex - 1 >= 0)
				{
				iPlainTextArray[--iIndex]->PreviousChunkL(*iChunk16, iStatus);
				SetActive();
				callComplete = EFalse;
				}
			break;	
			}
		default:
			{
			__ASSERT_DEBUG(iChunkRetrievalState != EIdleState, gPanic(EImcmIdleRetrievalState));
			break;
			}
		
		}
	if(callComplete)	
		{
		Complete(iStatus.Int());
		iChunkRetrievalState = EIdleState;
		}
	}

/**
Commits the email message after it has been completed.
@param aStatus      The  TRequestStatus parameter for this request.
@return void
*/
EXPORT_C void CImPlainBodyText::CommitL(TRequestStatus& aStatus)
	{
	iPlainTextArray[0]->CommitL();
	delete iStore;
	iStore = NULL;
	iStoreMessagePart = CImStoreMessagePart::StorePlainBodyTextL(aStatus, iMsvEntry, iMessageId);
	}


/**
Commits the email message after it has been completed along with mime header for this message.
@param aStatus      The TRequestStatus parameter for this request.
@param aMimeHeader  The CMimeHeader for this message.
@return void
*/
EXPORT_C void CImPlainBodyText::CommitL(TRequestStatus& aStatus, CImMimeHeader& aMimeHeader)
	{
	// Commit the file.This will close the plainbody text file.
	iPlainTextArray[0]->CommitL();
	delete iStore;
	iStore = NULL;
	iStoreMessagePart = CImStoreMessagePart::StorePlainBodyTextL(aStatus, iMsvEntry, iMessageId, aMimeHeader);
	}

/**
Cancels the relavent CMsvPlainBodyText object
*/	
void CImPlainBodyText::DoCancel()
	{
	iPlainTextArray[iIndex]->Cancel();
	}
