/*
* 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:  Email interface implementation.
*
*/
#include "msgstorewritablepropertycontainer.h"

#include "baseplugindelayedops.h"
#include "baseplugindelayedopsprivate.h"


///////////////////////////////////////////////////
// CDelayedOp                                    //
///////////////////////////////////////////////////

/**
 * 
 */
/*public virtual*/ EXPORT_C CDelayedOp::~CDelayedOp()
    {
    Cancel();
    __LOG_DESTRUCT
    }

/**
 * 
 */
/*public*/ EXPORT_C void CDelayedOp::SetContext(
    CBasePlugin& aPlugin, MDelayedOpsManager& aManager )
    {
    iPlugin = &aPlugin;
    iManager = &aManager;
    } 

/**
 * 
 */
/*protected*/ EXPORT_C CDelayedOp::CDelayedOp()
    : CAsyncOneShot( CActive::EPriorityIdle )
    {    
    }
    
/**
 * 
 */
/*private virtual*/ EXPORT_C void CDelayedOp::RunL()
    {
    __LOG_ENTER_SUPPRESS( "Run" );
    TRAPD( err, ExecuteOpL() );
    
    if ( KErrNone != err )
        {
        __LOG_WRITE8_FORMAT1_INFO(
            "Error while executing delayed operation: %d.", err );
        }
    
    //self-destroy.
    iManager->DequeueOp( *this );
    delete this;
    }
    
/**
 * 
 */
/*protected*/ EXPORT_C CBasePlugin& CDelayedOp::GetPlugin()
    {
    return *iPlugin;
    }

/**
 * 
 */
/*private virtual*/ EXPORT_C void CDelayedOp::DoCancel()
    {
    }


///////////////////////////////////////////////////
// CDelayedOpsManager                            //
///////////////////////////////////////////////////

/**
 * 
 */
/*static public*/
CDelayedOpsManager* CDelayedOpsManager::NewL( CBasePlugin& aPlugin )
    {
    CDelayedOpsManager* self = new (ELeave) CDelayedOpsManager( aPlugin );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }
    
/**
 * 
 */
/*public virtual*/ CDelayedOpsManager::~CDelayedOpsManager()
    {
    ExecutePendingOps();
    
    iDelayedOps.ResetAndDestroy();
    iDelayedOps.Close();
    
    __LOG_DESTRUCT
    }
    
/**
 * 
 */
/*public virtual*/ void CDelayedOpsManager::EnqueueOpL( CDelayedOp* aOp )
    {
    iDelayedOps.AppendL( aOp );
    aOp->SetContext( iPlugin, *this );        
    aOp->Call();
    }
    
/**
 * 
 */
/*public virtual*/ void CDelayedOpsManager::DequeueOp( const CDelayedOp& aOp )
    {
    TInt count = iDelayedOps.Count();
    for ( TInt i = 0; i < count; ++i )
        {
        CDelayedOp* op = iDelayedOps[i];
        if ( &aOp == op )
            {
            iDelayedOps.Remove( i );
            break;
            }
        }
    }
    
/**
 * 
 */
/*public virtual*/ TInt CDelayedOpsManager::Extension1(
    TUint /*aExtensionId*/, TAny*& /*a0*/, TAny* /*a1*/ )
    {
    return KErrNotSupported;
    }

/**
 * 
 */
/*private*/ CDelayedOpsManager::CDelayedOpsManager( CBasePlugin& aPlugin )
    : iPlugin ( aPlugin )
    {
    }

/**
 * 
 */
/*private*/ void CDelayedOpsManager::ConstructL()
    {
    __LOG_CONSTRUCT( "baseplugin", "CDelayedOpsManager" );
    }

/**
 * 
 */
/*private*/ void CDelayedOpsManager::ExecutePendingOps()
    {
    //check the count on every iteration to avoid missing operations being
    //enqueued by another operations.
    for ( TInt i = 0; i < iDelayedOps.Count(); ++i )
        {
        CDelayedOp* op = iDelayedOps[i];
        
        op->Cancel();
        TRAP_IGNORE( op->ExecuteOpL() );
        }
    }    


///////////////////////////////////////////////////
// CDelayedDeleteMessagesOp                      //
///////////////////////////////////////////////////

/**
 * 
 */
/*public static */ CDelayedDeleteMessagesOp* CDelayedDeleteMessagesOp::NewLC(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aFolderId,
    const RArray<TFSMailMsgId>& aMessages )
    {
    CDelayedDeleteMessagesOp* self = new (ELeave) CDelayedDeleteMessagesOp(
        aMailBoxId, aFolderId );
    CleanupStack::PushL( self );
    self->ConstructL( aMessages );
    return self;
    }

/**
 * 
 */
/*public static */ CDelayedDeleteMessagesOp* CDelayedDeleteMessagesOp::NewLC(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aFolderId,
    TMsgStoreId aMsgId )
    {
    CDelayedDeleteMessagesOp* self = new (ELeave) CDelayedDeleteMessagesOp(
        aMailBoxId, aFolderId );
    CleanupStack::PushL( self );
    self->ConstructL( aMsgId );
    return self;
    }

/**
 * 
 */
/*public virtual*/ CDelayedDeleteMessagesOp::~CDelayedDeleteMessagesOp()
    {
    iMessages.Close();
    __LOG_DESTRUCT
    }


/**
 * 
 */
/*private*/
void CDelayedDeleteMessagesOp::ConstructL(
    const RArray<TFSMailMsgId>& aMessages )
    {
    __LOG_CONSTRUCT( "baseplugin", "CDelayedDeleteMessagesOp" );
            
    TInt count = aMessages.Count();
    for ( TInt i = 0; i < count; ++i )
        {
        iMessages.AppendL( aMessages[i].Id() );
        }
    }

/**
 * 
 */
/*private*/
void CDelayedDeleteMessagesOp::ConstructL(
    TMsgStoreId aMsgId )
    {
    __LOG_CONSTRUCT( "baseplugin", "CDelayedDeleteMessagesOp" );
    iImmediateDelete = ETrue;
    iMessages.AppendL( aMsgId );
    }

/**
 * 
 */
/*private*/ CDelayedDeleteMessagesOp::CDelayedDeleteMessagesOp(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aFolderId )
    :
    iMailBoxId( aMailBoxId ), iFolderId( aFolderId ),
    iImmediateDelete( EFalse )
    {
    }

/**
 * 
 */
/*private*/ void CDelayedDeleteMessagesOp::ExecuteOpL()
    {
    __LOG_ENTER( "ExecuteOpL" );
    
    CMailboxInfo& mailBoxInfo
        = GetPlugin().GetMailboxInfoL( iMailBoxId );
    CMsgStoreMailBox& mailBox = mailBoxInfo();

    TInt count = iMessages.Count();
    for ( TInt i = 0; i < count; ++i )
        {
        TMsgStoreId msgId = iMessages[i];
        
        if ( EFalse == iImmediateDelete )
            {
            //try to find the message in the deleted items folder.
            CMsgStoreMessage* theMessage = NULL;
            TRAP_IGNORE( theMessage = mailBox.FetchMessageL(
              msgId, mailBoxInfo.iRootFolders.iFolders[EFSDeleted] ) );
            
            if ( NULL == theMessage )
                {
                //if not in deleted items then move it there.
                __LOG_WRITE8_FORMAT1_INFO(
                     "Moving message 0x%X to the deleted items.", msgId );
                mailBox.MoveMessageL(
                   msgId, KMsgStoreInvalidId,
                   mailBoxInfo.iRootFolders.iFolders[EFSDeleted] );
                }
            else
                {
                //in deleted items, really delete it.
                __LOG_WRITE8_FORMAT1_INFO( "Deleting message 0x%X.", msgId );

                delete theMessage;
                mailBox.DeleteMessageL( msgId, iFolderId );
                }
            }
        else
            {
            mailBox.DeleteMessageL( msgId, iFolderId );
            }
        }

    __LOG_EXIT;
    }


///////////////////////////////////////////////////
// CDelayedStorePropertiesOp                     //
///////////////////////////////////////////////////

/**
 * 
 */
/*public static*/
CDelayedSetContentOp* CDelayedSetContentOp::NewLC(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aMessageId,
    TMsgStoreId aMessagePartId,
    const TDesC& aContent )
    {
    CDelayedSetContentOp* self = new (ELeave) CDelayedSetContentOp(
        aMailBoxId, aMessageId, aMessagePartId );
    CleanupStack::PushL( self );
    self->ConstructL( aContent );
    return self;
    }

/**
 * 
 */
/*public static*/
CDelayedSetContentOp* CDelayedSetContentOp::NewLC(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aMessageId,
    TMsgStoreId aMessagePartId,
    TInt aContentLength )
    {
    CDelayedSetContentOp* self = new (ELeave) CDelayedSetContentOp(
        aMailBoxId, aMessageId, aMessagePartId, aContentLength );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

/**
 * 
 */
/*public virtual*/ CDelayedSetContentOp::~CDelayedSetContentOp()
    {
    delete iContent;
    
    __LOG_DESTRUCT
    }

/**
 * 
 */
/*private*/ void CDelayedSetContentOp::ConstructL( const TDesC& aContent )
    {
    __LOG_CONSTRUCT( "baseplugin", "CDelayedSetContentOp1" );
    
    iContent = aContent.AllocL();
    }

/**
 * 
 */
/*private*/ void CDelayedSetContentOp::ConstructL()
    {
    __LOG_CONSTRUCT( "baseplugin", "CDelayedSetContentOp2" );
    }

/**
 * CDelayedOp::ExecuteOpL
 */
/*public virtual*/ void CDelayedSetContentOp::ExecuteOpL()
    {
    __LOG_ENTER( "ExecuteOpL" )

    CMsgStoreMessagePart* part = FetchMessagePartLC();

    if ( iStepOne )
        {
        part->ReplaceContentL(
            TPtrC8( reinterpret_cast<const TUint8*>(
                iContent->Ptr() ), iContent->Size() ) );
        __LOG_WRITE8_FORMAT1_INFO(
            "Stored the content of part 0x%X.", part->Id() )
        }
    else
        {
        part->AddOrUpdatePropertyL(
            KMsgStorePropertySize, static_cast<TUint32>( iContentLength ) );
        part->AddOrUpdatePropertyL(
            KMsgStorePropertyRetrievedSize,
            static_cast<TUint32>( iContentLength ) );
        
        part->StorePropertiesL();
        __LOG_WRITE8_FORMAT1_INFO(
            "Updated the properties of part 0x%X.", part->Id() )
        }
    
    CleanupStack::PopAndDestroy( part );    
    __LOG_EXIT
    }

/**
 * 
 */
/*private*/ CMsgStoreMessagePart* CDelayedSetContentOp::FetchMessagePartLC()
    {
    __LOG_ENTER_SUPPRESS( "FetchMessagePartLC" )
    CMailboxInfo& mailBox = GetPlugin().GetMailboxInfoL( iMailBoxId );
    
    CMsgStoreMessage* msg = mailBox().FetchMessageL(
        iMessageId, KMsgStoreInvalidId );
    CleanupStack::PushL( msg );
    
    CMsgStoreMessagePart* part;
    if ( KMsgStoreInvalidId == iMessagePartId )
        {
        __LOG_WRITE_INFO( "Fetched the message itself." );
        //watch the cleanupstack, part will point to the same thing thus the
        //popanddestroy is ok.
        part = msg;
        }
    else
        {
        __LOG_WRITE_INFO( "Fetched a child part of the message." );
        part = msg->ChildPartL( iMessagePartId, ETrue );
        CleanupStack::PopAndDestroy( msg );
        CleanupStack::PushL( part );
        }
    
    return part;
    }

/**
 * 
 */
/*private*/ CDelayedSetContentOp::CDelayedSetContentOp(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aMessageId,
    TMsgStoreId aMessagePartId )
    : iMailBoxId( aMailBoxId ), iMessageId( aMessageId ),
      iMessagePartId( aMessagePartId ), iStepOne( ETrue )
    {
    }

/**
 * 
 */
/*private*/ CDelayedSetContentOp::CDelayedSetContentOp(
    TMsgStoreId aMailBoxId,
    TMsgStoreId aMessageId,
    TMsgStoreId aMessagePartId,
    TInt aContentLength )
    : iMailBoxId( aMailBoxId ), iMessageId( aMessageId ),
      iMessagePartId( aMessagePartId ), iContentLength( aContentLength ),
      iStepOne( EFalse )
    {
    }
