/*
* 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:  Implementation for Meeting request task factory
*
*/

#include "emailtrace.h"
#include "cmrtaskplugin.h"

#include "cesmrcombinedtask.h"
#include "cesmrstoremrtask.h"
#include "cesmrsendmrrespmailtask.h"
#include "cesmrdeletefromdbmrtask.h"
#include "cesmrsendmrrespfsmailtask.h"
#include "cesmrsendmrfsmailtask.h"
#include "cesmrforwardasfsmailtask.h"
#include "cesmrsendmrfsmailreplytask.h"

#include "mesmrmeetingrequestentry.h"
#include "cesmrconfirmationquery.h"
#include "cesmrlistquery.h"
#include "cesmrresponsedialog.h"
#include "tesmrinputparams.h"
#include "esmrconfig.hrh"
#include "cesmrcaldbmgr.h"
//<cmail>
#include "cfsmailcommon.h"
#include "cfsmailclient.h"
#include "cfsmailmessage.h"
#include "cfsmailbox.h"
//</cmail>


namespace {

#ifdef _DEBUG

// Panic literal for ESMRTaskFactory
_LIT( KESMRTaskFactoryPanicTxt, "MRTaskPlugin" );

/** Panic code definitions */
enum TESMRTaskFactoryPanic
    {
    EESMRTaskFactoryInvalidTask, // Trying to create invalid task
    EESMRTaskFactoryIllegalTask, // Task can not be performed for given entry.
    };


// ---------------------------------------------------------------------------
// Panic wrapper method
// ---------------------------------------------------------------------------
//
void Panic( TESMRTaskFactoryPanic aPanic )
    {

    User::Panic( KESMRTaskFactoryPanicTxt, aPanic );
    }

#endif // _DEBUG

/**
 * Checks whether reply mail is required by the plug-in or not.
 * @param aEntry Regerence to MR entry
 */
TBool ReplyMailRequiredL(
        MESMRMeetingRequestEntry& aEntry )
    {
    TBool replyNeeded( EFalse );

    TESMRInputParams esmrParams;
    if ( aEntry.IsOpenedFromMail() &&
         aEntry.StartupParameters(esmrParams) )
        {
        TFSMailMsgId mailboxId(
                esmrParams.iMailMessage->GetMailBoxId() );

        CFSMailBox* mailbox =
                esmrParams.iMailClient->GetMailBoxByUidL( mailboxId );
        CleanupStack::PushL( mailbox );

        if ( mailbox->HasCapability(EFSMBoxCapaMRRequiresReplyEmail ) )
            {
            replyNeeded = ETrue;
            }
        CleanupStack::PopAndDestroy( mailbox );
        mailbox = NULL;
        }

    return replyNeeded;
    }

// ---------------------------------------------------------------------------
// Queries response query from user.
// ---------------------------------------------------------------------------
//
HBufC* QuerySendResponseQueryFromUserL(
        TESMRCommand aCommand,
        TESMRResponseType& aResponseType,
        MESMRMeetingRequestEntry& aEntry )
    {
    HBufC* responseMessage = NULL;
    TInt ret = EESMRResponsePlain;

    TESMRAttendeeStatus status(
            EESMRAttendeeStatusDecline );

    // convert the command to status:
    switch ( aCommand )
        {
        case EESMRCmdAcceptMR:
            {
            status = EESMRAttendeeStatusAccept;
            break;
            }
        case EESMRCmdTentativeMR:
            {
            status = EESMRAttendeeStatusTentative;
            break;
            }
        case EESMRCmdDeclineMR:
            {
            status = EESMRAttendeeStatusDecline;
            break;
            }
        default:
            {
            // never should come here.
            User::Leave(KErrGeneral);
            break;
            }
        }

    TBool replyRequired( ReplyMailRequiredL(aEntry) );

    if ( replyRequired )
        {
        ret = CESMRListQuery::ExecuteEditBeforeSendWithSendOptOnlyL( status );
        }
    else
        {
        ret = CESMRListQuery::ExecuteEditBeforeSendL( status );
        }

    // User has selected cancel from dialog. Interrupt task execution,
    // leave will be trapped in cesmecontroller (esmrviewer module)
    if ( ret != KErrCancel )
        {
        if ( aEntry.IsRecurrentEventL() )
            {
            aEntry.SetModifyingRuleL( MESMRCalEntry::EESMRAllInSeries );
            }
        }
    else
        {
        User::Leave( KErrCancel );
        }

    aResponseType = static_cast<TESMRResponseType>(ret);

    // set the response status to cal entry:
    aEntry.ConstructReplyL(status);

    if ( EESMRResponseMessage == aResponseType )
        {
        CESMRResponseDialog* respDlg =
                CESMRResponseDialog::NewL( responseMessage );
        CleanupStack::PushL( respDlg );

        TInt dialogRetValue( respDlg->ExecuteDlgLD() );
        // Dialog has deleted itself --> Only pop from cleanup stack
        CleanupStack::Pop( respDlg );

        if ( !dialogRetValue )
            {
			aEntry.Entry().SetStatusL( CCalEntry::ETentative );
            User::Leave( KErrCancel );
            }
        else if ( dialogRetValue == EAknCmdExit )
        	{
    		aResponseType = EESMRResponseDontSend;
        	}
        else if ( !responseMessage
                  && dialogRetValue == EESMRCmdSendMR )
            {
            // Send command is triggered but response is empty
            aResponseType = EESMRResponsePlain;
            responseMessage = KNullDesC().AllocL();
            }
        }
    else
    	{
		responseMessage = KNullDesC().AllocL();
    	}

    return responseMessage;
    }

} // namespace

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CMRTaskPlugin
// ---------------------------------------------------------------------------
//
inline CMRTaskPlugin::CMRTaskPlugin( MESMRCalDbMgr& aCalDbMgr )
    : iCalDbMgr( aCalDbMgr )
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::~CMRTaskPlugin
// ---------------------------------------------------------------------------
//
CMRTaskPlugin::~CMRTaskPlugin()
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::TaskFactory
// ---------------------------------------------------------------------------
//
CMRTaskPlugin* CMRTaskPlugin::NewL( TAny* aCalDbMgr )
    {
    FUNC_LOG;

    MESMRCalDbMgr* calDbMgr = static_cast< MESMRCalDbMgr* >( aCalDbMgr );
    CMRTaskPlugin* self = new(ELeave) CMRTaskPlugin( *calDbMgr );

    return self;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateTaskL(
            TESMRCommand aCommand,
            MESMRCalEntry& aEntry )
    {
    FUNC_LOG;

    MESMRTask* task = NULL;

    MESMRMeetingRequestEntry& mrEntry =
        static_cast< MESMRMeetingRequestEntry& >( aEntry );

    switch (aCommand)
        {
        case EESMRCmdAcceptMR:
        case EESMRCmdTentativeMR:
        case EESMRCmdDeclineMR:
            task = CreateSendMRResponseViaMailTaskL( aCommand, mrEntry );
            break;

        case EESMRCmdSendMR:
        case EESMRCmdSendMRUpdate:
            task = CreateSendMRTaskL( aCommand, mrEntry );
            break;

        case EESMRCmdDeleteMR:
        case EESMRCmdRemoveFromCalendar:
        case EESMRCmdMailDelete:
            task = CreateDeleteMRTaskL( aCommand, mrEntry );
            break;

        case EESMRCmdSaveMR:
            task = CreateStoreMRToLocalDBTaskL( aCommand, mrEntry );
            break;

        case EESMRCmdForwardAsMeeting:
            task = CreateForwardAsMeetingTaskL( aCommand, mrEntry );
            break;

        case EESMRCmdForwardAsMail:
            task = CreateForwardAsMailTaskL( mrEntry );
            break;
        case EESMRCmdReplyAll:
            task = CreateReplyAsMailTaskL( mrEntry, ETrue );
            break;

        case EESMRCmdReply:
            task = CreateReplyAsMailTaskL( mrEntry, EFalse );
            break;

        case EESMRCmdCalendarChange:
            task = CreateMoveMRToCurrentDBTaskL( mrEntry );
            break;

        default:
            __ASSERT_DEBUG(EFalse, Panic(EESMRTaskFactoryInvalidTask) );
            User::Leave( KErrNotSupported );
            break;
        }


    return task;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateSendMRResponseViaMailTask
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateSendMRResponseViaMailTaskL(
            TESMRCommand aCommand,
            MESMRMeetingRequestEntry& aEntry )
    {
    FUNC_LOG;

    CESMRCombinedTask* task = NULL;
    TESMRRole role = aEntry.RoleL();

    TBool syncObjectPresent( aEntry.IsSyncObjectPresent() );
    TBool isStored( aEntry.IsStoredL() );

    if ( EESMRRoleRequiredAttendee == role  ||
         EESMRRoleOptionalAttendee == role  ||
         EESMRRoleNonParticipant == role )
        {
        task = CESMRCombinedTask::NewL( aEntry,
                                        CESMRCombinedTask::EESMRTrap );

        CleanupStack::PushL( task );

        TESMRResponseType responseType( EESMRResponsePlain );
        HBufC* responseMessage = QuerySendResponseQueryFromUserL(
                aCommand,
                responseType,
                aEntry );

        // If response message is NULL, it means that user
        // has cancelled response editing and wants to only exit
        // application
        if( responseMessage )
        	{
			CleanupStack::PushL( responseMessage );

			if ( !syncObjectPresent && EESMRCmdDeclineMR != aCommand)
				{
				// Entry is stored or deleted from calendar DB if
				// sync object is not present
				// Store MR task
				AppendTaskL( *task,
							 CESMRStoreMRTask::NewL(
							 iCalDbMgr,
							 aEntry,
							 aEntry.MailboxUtils() ) );
				}

			if ( EESMRResponseDontSend != responseType )
				{
				// Send MR response via mail freestyle task
				AppendTaskL( *task,
							CESMRSendMRRespFSMailTask::NewL(
									aCommand,
									iCalDbMgr,
									aEntry,
									aEntry.MailboxUtils(),
									responseType,
									*responseMessage ) );
				}

			CleanupStack::PopAndDestroy( responseMessage );

			if ( !syncObjectPresent && EESMRCmdDeclineMR == aCommand &&
					isStored )
				{
				// Entry is deleted from calendar DB if
				// sync object is not present and entry exits in database
				// Declined --> Delete MR from cal DB task
				AppendTaskL( *task,
							CESMRDeleteMRFromDbTask::NewL(
							iCalDbMgr,
							aEntry,
							aEntry.MailboxUtils() ) );
				}
	       	}

		CleanupStack::Pop( task );
        }
    else
        {
        // Only (opt-)attendees and non-participants can send
        // responses
        User::Leave( KErrNotSupported );
        }


    return task;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateSendMRTask
// ---------------------------------------------------------------------------
//

MESMRTask* CMRTaskPlugin::CreateSendMRTaskL(
            TESMRCommand aCommand,
            MESMRMeetingRequestEntry& aEntry )
    {
    FUNC_LOG;

    CESMRCombinedTask* task = CESMRCombinedTask::NewL( aEntry );

    CleanupStack::PushL( task );

    if ( !aEntry.IsForwardedL() )
        {
        // Store MR task
        AppendTaskL( *task,
                    CESMRStoreMRTask::NewL(
                    iCalDbMgr,
                    aEntry,
                    aEntry.MailboxUtils() ) );
        }

    if ( !aEntry.OccursInPastL() )
        {
        if ( aCommand == EESMRCmdSendMR ||
             aCommand == EESMRCmdSendMRUpdate )
            {
            // Send MR response via mail task
            AppendTaskL( *task,
                        CESMRSendMRFSMailTask::NewL(
                        iCalDbMgr,
                        aEntry,
                        aEntry.MailboxUtils(),
                        aCommand ) );
            }
        }

    CleanupStack::Pop( task );


    return task;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateDeleteMRTask
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateDeleteMRTaskL(
            TESMRCommand aCommand,
            MESMRMeetingRequestEntry& aEntry )
    {
    FUNC_LOG;

    MESMRTask* task = NULL;

    if ( EESMRRoleOrganizer == aEntry.RoleL() )
        {
        task = CreateOrganizerDeleteMRTaskL( aCommand, aEntry );
        }
    else
        {
        task = CreateAttendeeDeleteMRTaskL( aCommand, aEntry );
        }


    return task;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateStoreMRToLocalDBTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateStoreMRToLocalDBTaskL(
        TESMRCommand /*aCommand*/,
        MESMRMeetingRequestEntry& aEntry )
    {
    FUNC_LOG;
    return CESMRStoreMRTask::NewL(
                iCalDbMgr,
                aEntry,
                aEntry.MailboxUtils() );
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateForwardAsMeetingTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateForwardAsMeetingTaskL(
            TESMRCommand aCommand,
            MESMRMeetingRequestEntry& aEntry  )
    {
    FUNC_LOG;
    MESMRTask* task = NULL;

    // Send MR response via mail task is used for forwarding as meeting request

    if ( aCommand == EESMRCmdForwardAsMeeting )
        {
        task =  CESMRSendMRFSMailTask::NewL(
                        iCalDbMgr,
                        aEntry,
                        aEntry.MailboxUtils(),
                        aCommand );
        }
    return task;
    }



// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateForwardAsMeetingTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateForwardAsMailTaskL(
            MESMRMeetingRequestEntry& aEntry  )
    {
    FUNC_LOG;
    // Send MR response via mail task
    return CESMRForwardAsFSMailTask::NewL(
                iCalDbMgr,
                aEntry,
                aEntry.MailboxUtils() );
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateReplyAsMailTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateReplyAsMailTaskL(
            MESMRMeetingRequestEntry& aEntry, TBool aReplyAll  )
    {
    FUNC_LOG;
    // Send MR reply via mail task
    return CESMRSendMRFSMailReplyTask::NewL(
                iCalDbMgr,
                aEntry,
                aEntry.MailboxUtils(),
                aReplyAll);

    }


// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateOrganizerDeleteMRTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateOrganizerDeleteMRTaskL(
        TESMRCommand aCommand,
        MESMRMeetingRequestEntry& aEntry )
    {
    FUNC_LOG;

    CESMRCombinedTask* task = CESMRCombinedTask::NewL(
                                    aEntry,
                                    CESMRCombinedTask::EESMRTrap );

    CleanupStack::PushL( task );

    if ( EESMRCmdDeleteMR == aCommand )
        {
        // SYNC_SOLUTION requires the modified entry to be stored into
        // calendar db for deletion purposes.
        AppendTaskL( *task,
                CESMRStoreMRTask::NewL(
                        iCalDbMgr,
                        aEntry,
                        aEntry.MailboxUtils() ) );

        TUint attendeeFlags(
                EESMRRoleRequiredAttendee | EESMRRoleOptionalAttendee);
        if ( aEntry.AttendeeCountL( attendeeFlags ) && aEntry.IsSentL()
        		&& !aEntry.OccursInPastL() )
        	{
        	// If entry doesn't need to send cancellation, don't query
        	if( aEntry.SendCanellationAvailable())
        		{
        		// Meeting request contains attendees --> Cancellation message
        		// needs to be sent
        		if ( CESMRConfirmationQuery::ExecuteL(
        				CESMRConfirmationQuery::EESMRSendCancellationInfoToParticipants) )
        			{
        			AppendTaskL( *task,
        					CESMRSendMRFSMailTask::NewL(
        							iCalDbMgr,
        							aEntry,
        							aEntry.MailboxUtils(),
        							aCommand ) );
        			}
        		}
        	aEntry.SetSendCanellationAvailable( ETrue );
        	}
        }

    // Delete MR from cal DB task
    AppendTaskL( *task,
                CESMRDeleteMRFromDbTask::NewL(
                iCalDbMgr,
                aEntry,
                aEntry.MailboxUtils() ) );

    CleanupStack::Pop( task );


    return task;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateAttendeeDeleteMRTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateAttendeeDeleteMRTaskL(
        TESMRCommand aCommand,
        MESMRMeetingRequestEntry& aEntry )
    {
    FUNC_LOG;

    TBool pluginRequiresReplyMail( ReplyMailRequiredL(aEntry) );

    CESMRCombinedTask* task = CESMRCombinedTask::NewL(
                                    aEntry,
                                    CESMRCombinedTask::EESMRTrap );

    CleanupStack::PushL( task );

    if ( !aEntry.IsOpenedFromMail() && !aEntry.IsSyncObjectPresent() )
        {
        // When deleting from the calendar --> Store first modifying entry
        // And then delete that from calendar DB.
        //
        // When opened from mail --> We do not need to store
        // modifying entry into calendar database.
        //
        AppendTaskL( *task,
                CESMRStoreMRTask::NewL(
                        iCalDbMgr,
                        aEntry,
                        aEntry.MailboxUtils() ) );
        }


    if ( EESMRCmdDeleteMR == aCommand   ||
         EESMRCmdMailDelete == aCommand   ||
         (pluginRequiresReplyMail && EESMRCmdRemoveFromCalendar == aCommand ) )
        {
        TBool sendDecline(EFalse);

        if ( pluginRequiresReplyMail )
            {
            sendDecline = ETrue;
            }
        else
            {
            sendDecline = CESMRConfirmationQuery::ExecuteL(
                    CESMRConfirmationQuery::EESMRSendDecline );
            }

        if( sendDecline )
            {
            // Send MR response via mail task. No response message is appended
            // to sent email

            TESMRCommand command( EESMRCmdDeclineMR );

            if ( pluginRequiresReplyMail && EESMRCmdRemoveFromCalendar == aCommand  )
                {
                command = EESMRCmdRemoveFromCalendar;
                }

            AppendTaskL( *task,
                        CESMRSendMRRespFSMailTask::NewL(
                                command,
                                iCalDbMgr,
                                aEntry,
                                aEntry.MailboxUtils(),
                                EESMRResponsePlain,
                                KNullDesC() ) );
            }
        }

    // Delete MR from cal DB task if plugin does not handle it
    if ( !pluginRequiresReplyMail )
        {
        AppendTaskL( *task,
            CESMRDeleteMRFromDbTask::NewL(
            iCalDbMgr,
            aEntry,
            aEntry.MailboxUtils() ) );
        }

    CleanupStack::Pop( task );


    return task;
    }

// ---------------------------------------------------------------------------
// CMRTaskPlugin::CreateMoveMRToCurrentDBTaskL
// ---------------------------------------------------------------------------
//
MESMRTask* CMRTaskPlugin::CreateMoveMRToCurrentDBTaskL(
            MESMRMeetingRequestEntry& aEntry )
    {
    // Check first that entry can be moved
    if ( aEntry.IsSyncObjectPresent() )
        {
        __ASSERT_DEBUG( EFalse, Panic( EESMRTaskFactoryIllegalTask ) );
        User::Leave( KErrNotSupported );
        }

    // Create combined task
    CESMRCombinedTask* task = CESMRCombinedTask::NewL(
            aEntry,
            CESMRCombinedTask::EESMRTrap );

    CleanupStack::PushL( task );

    if ( !aEntry.IsOpenedFromMail() )
        {
        // When deleting from the calendar --> Store first modifying entry
        // And then delete that from calendar DB.
        //
        // When opened from mail --> We do not need to store
        // modifying entry into calendar database.
        //
        AppendTaskL(
                *task,
                CESMRStoreMRTask::NewL(
                        iCalDbMgr,
                        aEntry,
                        aEntry.MailboxUtils() ) );
        }

    // Delete entry from old db
    AppendTaskL(
            *task,
            CESMRDeleteMRFromDbTask::NewL(
                    iCalDbMgr,
                    aEntry,
                    aEntry.MailboxUtils() ) );

    // Store entry to current db
    AppendTaskL(
            *task,
            CESMRStoreMRTask::NewL(
                    iCalDbMgr,
                    aEntry,
                    aEntry.MailboxUtils() ) );

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

// EOF

