/*
* Copyright (c) 2006 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:  Message store multipart message client support implementation.
*
*/



//<cmail>
#include "msgstoremessagepart.h"
#include "msgstorepropertykeys.h"
//</cmail>
#include "msgstoresessioncontext.h"
#include "rmessagestoresession.h"
#include "MessageStoreClientServer.h"
#include "msgstoremessage.h"

//_LIT( KTextPlain, "text/plain" );
//_LIT( KTextHTML, "text/html" );
_LIT(KFSMailContentTypeMultipartAlternative, "multipart/alternative");


// ========================
// CLASS: TPartsArray
// ========================
class TPartsArray : public MPropertiesArray
    {
    public:
    
	    // ==============
	    // PUBLIC METHODS
	    // ==============
	    
        TPartsArray( CMsgStoreSessionContext& aContext, TMsgStoreId aMailBoxId, RPointerArray<CMsgStoreMessagePart>& aParts );
        
        // inherited from MPropertiesArray              
        virtual void AddElementL( TMsgStoreId aId, TMsgStoreId aParentId, const TDesC8& aProperties );
        virtual void Reset();        
        
    private:
    
 	    // ==================
	    // PRIVATE ATTRIBUTES
	    // ==================
	
        CMsgStoreSessionContext&             iContext;
        TMsgStoreId                          iMailBoxId;
        RPointerArray<CMsgStoreMessagePart>& iParts;
        
    }; // end class TPartsArray

    
// ==========================================================================
// FUNCTION: Constructor
// ==========================================================================
TPartsArray::TPartsArray( CMsgStoreSessionContext& aContext, TMsgStoreId aMailBoxId, RPointerArray<CMsgStoreMessagePart>& aParts ) : 
    iContext( aContext ), iMailBoxId( aMailBoxId ), iParts( aParts ) 
    {
    } // end constructor
       
// ==========================================================================
// FUNCTION: AddElementL
// ==========================================================================
void TPartsArray::AddElementL( TMsgStoreId aId, TMsgStoreId aParentId, const TDesC8& aProperties )
    {
    CMsgStoreMessagePart *newPart = CMsgStoreMessagePart::NewL( iContext, aId, aParentId, iMailBoxId, aProperties );
    CleanupStack::PushL( newPart );
    
    iParts.AppendL( newPart );    
    
    CleanupStack::Pop( newPart );
    } // end AddElementL
    
// ==========================================================================
// FUNCTION: Reset
// ==========================================================================
void TPartsArray::Reset()
    {
    iParts.ResetAndDestroy();
    } // end Reset
    

/** Adds a child part to this part 

    /param aProperties the headers of the newly added part
    /note This method leaves with KErrNotSupported if it is NOT multi-part, i.e. this part
    already has content.
 */
EXPORT_C CMsgStoreMessagePart* CMsgStoreMessagePart::AddChildPartL( const CMsgStorePropertyContainer& aProperties,
                                                                    const TDesC& aContentFilename                 )
	{
	RBuf8 serializedProperties;
	CleanupClosePushL( serializedProperties );
	aProperties.SerializeL( serializedProperties );
	
	TInt partId = iContext.iSession.CreateContainerL( Id(), 
													  KMsgStoreInvalidId,   //do not check grand parent id
													  iMailBoxId,
													  EMsgStorePartBits,
													  serializedProperties,
													  ETrue,
                                                      aContentFilename );
	
	CMsgStoreMessagePart* part = CMsgStoreMessagePart::NewL( iContext, partId, Id(), iMailBoxId, serializedProperties );
	
	CleanupStack::PopAndDestroy( &serializedProperties );
	
	return part;
	}
		

/** Adds a child part to this part and set the content to the same content stored in the input file handle 

    /param aProperties the headers of the newly added part
            /param aFile file handle that contains the content.
    /note This method leaves with KErrNotSupported if it is NOT multi-part, i.e. this part
    already has content.
 */
EXPORT_C CMsgStoreMessagePart* CMsgStoreMessagePart::AddChildPartL( const CMsgStorePropertyContainer& aProperties,
                                                                    RFile& aFile )
	{
	RBuf8 serializedProperties;
	serializedProperties.CleanupClosePushL();
	aProperties.SerializeL( serializedProperties );
	
	TInt partId = iContext.iSession.CreateContainerL( Id(), 
													  KMsgStoreInvalidId,   //do not check grand parent id
													  iMailBoxId,
													  EMsgStorePartBits,
													  serializedProperties,
													  ETrue,
													  aFile );
	
	CMsgStoreMessagePart* part = CMsgStoreMessagePart::NewL( iContext, partId, Id(), iMailBoxId, serializedProperties );
	
	CleanupStack::PopAndDestroy( &serializedProperties );
	
	return part;
	}


/** Adds an existing part to the child 

    /param aPart already created child part
    /note This method leaves with KErrNotSupported if it is NOT multi-part, i.e. this part
    already has content.
 */

EXPORT_C CMsgStoreMessage* CMsgStoreMessagePart::AddChildMessageL( CMsgStorePropertyContainer& aProperties )
	{
	aProperties.AddOrUpdatePropertyL( KMsgStorePropertyIsEmbeddedMsg, ETrue );

	return static_cast<CMsgStoreMessage*>( AddChildPartL( aProperties ) );
	}


/** Copies an attachment from one message to another message.
	
	This function copies an an attachment, including the properties and content, from one
	message to another message.  This function will leave with KErrNotFound if the specified
	message is not found in the source folder or if the destination message is not found in
	the destination folder.

    KMsgStoreInvalidId may be passed for the destination folder ID if there is no desire to 
    check the source folder.
    
	ECapabilityWriteUserData is required to use this function.			
	
	\retval Returns the ID of the new message.

    \note Only works if the store is in an authenticated state, otherwise this function leaves
          with KErrNotReady.
*/		
EXPORT_C TMsgStoreId CMsgStoreMessagePart::CopyChildPartL( TMsgStoreId aPartId, TMsgStoreId aNewParentId )
	{
	iContext.VerifyTypeL( aPartId, EMsgStorePartBits );
	//new parent can be a message or a part
	iContext.VerifyTypeL( aNewParentId, EMsgStoreMessageBits, EMsgStorePartBits );
	
	return iContext.iSession.CopyContainerL( aPartId, 
	                                         Id(), 
	                                         KMsgStoreInvalidId,     //don't care
	                                         aNewParentId,
	                                         KMsgStoreInvalidId,     //don't care
	                                         iMailBoxId);	
	} // end CopyMessageL


/** Removes a child part from this part 

    /note This method leaves with KErrNotSupported if it is NOT multi-part.
 */
EXPORT_C void CMsgStoreMessagePart::RemoveChildPartL( TMsgStoreId aPartId, TBool aRecursive )
	{
	iContext.VerifyTypeL( aPartId, EMsgStorePartBits );
    
    TMsgStoreId parentId = ( aRecursive ? KMsgStoreInvalidId : Id() );
	
	iContext.iSession.DeleteContainerL( aPartId, parentId, KMsgStoreInvalidId, iMailBoxId );
	}

/** gets a child part fo this part 
    /note This method leaves with KErrNotSupported if it is NOT multi-part.
 */
EXPORT_C CMsgStoreMessagePart* CMsgStoreMessagePart::ChildPartL( TMsgStoreId aPartId, TBool aRecursive  )
	{
	iContext.VerifyTypeL( aPartId, EMsgStorePartBits );
	
	TMsgStoreId parentId = ( aRecursive ? KMsgStoreInvalidId : Id() );
	
	RBuf8 propertiesBuf;
	CleanupClosePushL( propertiesBuf );
	
	iContext.iSession.ContainerPropertiesL( aPartId, parentId, KMsgStoreInvalidId, propertiesBuf );	
	
	if ( !aRecursive && parentId != Id() )
		{
		//the part may have been moved, so it is no longer a child of this part
		User::Leave( KErrNotFound );
		}
	
	CMsgStoreMessagePart* part = CMsgStoreMessagePart::NewL( iContext, aPartId, parentId, iMailBoxId, propertiesBuf );
	
	CleanupStack::PopAndDestroy( &propertiesBuf );
	
	return part;
	}

/** list all the child part to this part 
    /note This method leaves with KErrNotSupported if it is NOT multi-part.
*/
EXPORT_C void CMsgStoreMessagePart::ChildPartsL( RPointerArray<CMsgStoreMessagePart>& aParts )
{
	
	TPartsArray partsArray( iContext, iMailBoxId, aParts );
	
	iContext.iSession.ChildrenPropertiesL( iId,               // aId
	                                       iParentId,         // aParentId
	                                       EMsgStorePartBits, // aContainerType
	                                       EFalse,            // aQuickProperties
	                                       EFalse,            // aRecursive	                                        	                                        
	                                       partsArray );	
	
	// make sure body come before attachments
	TInt count = aParts.Count(); 
	if ( count > 1 )
		{
		for ( TInt i = 0 ; i < count; i++ )
			{
			CMsgStoreMessagePart* part = aParts[i];
			TUint index = 0;
			if ( part->FindProperty( KMsgStorePropertyContentType, index ) )
				{
				const TDesC& contentType = part->PropertyValueDesL( index );
				if ( contentType == KFSMailContentTypeMultipartAlternative )
					{
						if( i > 0 )  
							{
							//body is not the first child, move it to the first place
							aParts.Remove(i);
							aParts.Insert( part, 0 );
							}
						break;
					}
				}
			}
		}
}

EXPORT_C TBool CMsgStoreMessagePart::IsEmbeddedMessageL()
	{
	
	TUint index;
	TBool isEmbeddedMsg = EFalse;
	
	if ( FindProperty( KMsgStorePropertyIsEmbeddedMsg, index ) )
		{
		isEmbeddedMsg = PropertyValueBoolL( index );
		}
	
	return isEmbeddedMsg;
	
	}


CMsgStoreMessagePart* CMsgStoreMessagePart::NewL( CMsgStoreSessionContext& aSessionContext, 
												  TMsgStoreId              aId, 
												  TMsgStoreId              aParentId, 
												  TMsgStoreId              aMailBoxId,
												  const TDesC8&            aPropertiesBuf )
	{												  
	CMsgStoreMessagePart* self = new( ELeave ) CMsgStoreMessagePart( aSessionContext, aId, aParentId, aMailBoxId );
	CleanupStack::PushL( self );
	self->ConstructL( aPropertiesBuf );
	
	//check if the flag is embedded message exists
	if ( self->IsEmbeddedMessageL() )
		{
		CleanupStack::PopAndDestroy( self );
		//create an instance of embedded message
		self = CMsgStoreMessage::NewL( aSessionContext, aId, aParentId, KMsgStoreInvalidId, aMailBoxId, aPropertiesBuf );
		}
	else
		{
		CleanupStack::Pop( self );
		}
	
	return self;
	}

void CMsgStoreMessagePart::ConstructL( const TDesC8& aPropertiesBuf )
	{
	DeserializeL( aPropertiesBuf );
	}

CMsgStoreMessagePart::CMsgStoreMessagePart( CMsgStoreSessionContext& aSessionContext, TMsgStoreId aId, TMsgStoreId aParentId, TMsgStoreId aMailBoxId )
: CMsgStorePropertyContainerWithContent( aSessionContext, aId, aParentId, aMailBoxId )
	{
	}
		

		
