/*
* Copyright (c) 2005-2007 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:  Phonebook 2 Group UI Extension send message command.
*
*/


// INCLUDE FILES
#include "CPguSendMessageGroupCmd.h"
#include "CPguUIExtensionPlugin.h"

// Phonebook 2
#include "MPbk2ProcessDecorator.h"
#include <MPbk2ContactNameFormatter.h>
#include <MPbk2ContactUiControl.h>
#include <MPbk2CommandObserver.h>
#include <Pbk2UIControls.rsg>
#include <TPbk2AddressSelectParams.h>
#include <CPbk2AddressSelect.h>
#include <MPbk2AppUi.h>
#include <MPbk2ApplicationServices.h>

// Virtual Phonebook
#include <VPbkFieldType.hrh>
#include <CVPbkContactManager.h>
#include <MVPbkContactLink.h>
#include <MVPbkContactOperationBase.h>
#include <MVPbkStoreContact.h>
#include <MVPbkContactFieldTextData.h>
#include <MVPbkStoreContactFieldCollection.h>
#include <RVPbkContactFieldDefaultPriorities.h>
#include <MVPbkContactGroup.h>
#include <MVPbkContactLinkArray.h>

// System includes
#include <featmgr.h>
#include <coemain.h>
#include <barsread.h>
#include <sendui.h>
#include <SenduiMtmUids.h>
#include <CMessageData.h>
#include <eikenv.h>

// Debugging headers
#include <Pbk2Debug.h>

/// Unnamed namespace for local definitions
namespace {

const TInt KDefaultTitleFormat = MPbk2ContactNameFormatter::EUseSeparator;
const TInt KGranularity( 4 );

#ifdef _DEBUG

enum TPanicCode
    {
    EPanicUnknownMedia = 1,
    ERunL_InvalidState,
    EPanicLogic
    };

void Panic(TPanicCode aReason)
    {
    _LIT(KPanicText, "CPguSendMessageGroupCmd");
    User::Panic(KPanicText,aReason);
    }

#endif // _DEBUG

}  /// namespace

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::CPguSendMessageGroupCmd
// --------------------------------------------------------------------------
//
CPguSendMessageGroupCmd::CPguSendMessageGroupCmd(
        MPbk2ContactUiControl& aUiControl, 
        CPguUIExtensionPlugin* aPguUIExtensionPlugin ) :
    CActive( EPriorityIdle ),
    iUiControl( &aUiControl ),
    iPguUIExtensionPlugin( aPguUIExtensionPlugin )   
    {
    CActiveScheduler::Add( this );
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::~CPguSendMessageGroupCmd
// --------------------------------------------------------------------------
//
CPguSendMessageGroupCmd::~CPguSendMessageGroupCmd()
    {
    Cancel();
    
    if( iUiControl )
        {
        iUiControl->RegisterCommand( NULL );
        }
		
    delete iMessageData;  
    delete iSelectedContacts;
    delete iMtmFilter;
    delete iRetrieveOperation;
    delete iStoreContact;
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::NewL
// --------------------------------------------------------------------------
//
CPguSendMessageGroupCmd* CPguSendMessageGroupCmd::NewL
        ( MPbk2ContactUiControl& aUiControl,
		      CPguUIExtensionPlugin*  aPguUIExtensionPlugin ) 
    {
    CPguSendMessageGroupCmd* self =
        new ( ELeave ) CPguSendMessageGroupCmd( aUiControl,
            aPguUIExtensionPlugin );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ConstructL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::ConstructL()
    {
    
    iUiControl->RegisterCommand( this );
    
    iFieldPropertyArray = &Phonebook2::Pbk2AppUi()->
        ApplicationServices().FieldProperties();

    iMtmFilter = new(ELeave) CArrayFixFlat<TUid>( KGranularity );
    iMtmFilter->AppendL(KSenduiMtmPostcardUid);  // hide postcard

    iSendingCapabilities.iFlags = TSendingCapabilities::ESupportsEditor;
    iSelectedContacts = iUiControl->SelectedContactsOrFocusedContactL();
    iMessageData = CMessageData::NewL();
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ExecuteLD
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::ExecuteLD()
    {
    iCurrentContactLinkIndex = 0;
    iState = EShowWriteQuery;
    IssueRequest();
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::AddObserver
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::AddObserver( MPbk2CommandObserver& aObserver )
    {
    iCommandObserver = &aObserver;
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ResetUiControl
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::ResetUiControl(
        MPbk2ContactUiControl& aUiControl)
    {
    if (iUiControl == &aUiControl)
        {
        iUiControl = NULL;
        }
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::DoCancel
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::DoCancel()
    {
    //Do nothing
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::RunL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::RunL()
    {
    switch ( iState )
        {
        case ERetrieving:
            {
            if ( iSelectedContacts )
                {
                if ( iSelectedContacts->Count() == iCurrentContactLinkIndex )
                    {
                    iState = EStarting;
                    IssueRequest();
                    }
                    else
                    {
                    RetrieveContactL( iSelectedContacts->At(
                                            iCurrentContactLinkIndex ) );
                    iCurrentContactLinkIndex++;
                    }
                }
            else
                {
                iState = EStopping;
                IssueRequest();
                }
            break;
            }
        case EShowWriteQuery:
            {
            iMtmUid = ShowWriteQueryL();
            if ( iMtmUid == KNullUid )
                {
                iState = EStopping;
                // Disconnect the relationship between control and command
                iUiControl->RegisterCommand( NULL );
                iUiControl = NULL;
                }
            else
                {
                iState = ERetrieving;
                }
            IssueRequest();
            break;
            }
        case EResolveGroup:
            {
            ResolveGroupL();
            break;
            }
        case EResolveURL:
            {
            ResolveUrlL();
            break;
            }
        case EStarting:
            {
            DoSendMessageL();
            break;
            }
        case EStopping:
            {
            ProcessDismissed( KErrNone );
            break;
            }
        default:
            {
            __ASSERT_DEBUG(EFalse, Panic(ERunL_InvalidState));
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::RunError
// --------------------------------------------------------------------------
//
TInt CPguSendMessageGroupCmd::RunError( TInt aError )
    {
    return FilterErrors( aError );
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::VPbkSingleContactOperationComplete
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::VPbkSingleContactOperationComplete(
        MVPbkContactOperationBase& aOperation,
        MVPbkStoreContact* aContact )
    {
    if ( &aOperation == iRetrieveOperation )
        {
        delete iRetrieveOperation;
        iRetrieveOperation = NULL;

        // We now have a store contact
        delete iStoreContact;
        iStoreContact = aContact;

        if ( iStoreContact->Group() )
            {
            iState = EResolveGroup;
            IssueRequest();
            }
        else
            {
            iState = EResolveURL;
            IssueRequest();
            }
        }
    else
        {
        IssueStopRequest();
        }
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::VPbkSingleContactOperationFailed
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::VPbkSingleContactOperationFailed(
        MVPbkContactOperationBase& aOperation,
        TInt aError )
    {
    if ( &aOperation == iRetrieveOperation )
        {
        delete iRetrieveOperation;
        iRetrieveOperation = NULL;

        // We cannot get the contact, so we have to
        // fail. We cannot continue, since this operation
        // was executed only in case of one contact.
        ProcessDismissed( aError );
        }
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ShowWriteQueryL
// --------------------------------------------------------------------------
//
TUid CPguSendMessageGroupCmd::ShowWriteQueryL()
    {
    TUid uid = Phonebook2::Pbk2AppUi()->ApplicationServices().SendUiL()->
        ShowTypedQueryL( CSendUi::EWriteMenu, NULL, iSendingCapabilities,
            iMtmFilter );
    return uid;
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::RetrieveContactL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::RetrieveContactL(
        const MVPbkContactLink& aContactLink )
    {
    // Retrieve the actual store contact from the given link
    iRetrieveOperation = Phonebook2::Pbk2AppUi()->ApplicationServices().
        ContactManager().RetrieveContactL( aContactLink, *this );
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::DoSendMessageL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::DoSendMessageL()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPguSendMessageGroupCmd::DoSendMessageL() start") );

    Phonebook2::Pbk2AppUi()->ApplicationServices().SendUiL()->
        CreateAndSendMessageL( iMtmUid, iMessageData );
    iState = EStopping;
    IssueRequest();
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ResolveGroupL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::ResolveGroupL()
    {
    MVPbkContactLinkArray* linkArray =
        iStoreContact->Group()->ItemsContainedLC();
    CleanupStack::Pop(); //linkArray

    delete iSelectedContacts;
    iSelectedContacts = linkArray;
    iCurrentContactLinkIndex = 0;

    iState = ERetrieving;
    IssueRequest();
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ResolveUrlL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::ResolveUrlL()
    {
    TResourceReader resReader;
    TUid techTypeUid = Phonebook2::Pbk2AppUi()->ApplicationServices().
        SendUiL()->TechnologyType( iMtmUid );

    RVPbkContactFieldDefaultPriorities defaults;
    CleanupClosePushL( defaults );

    TInt resourceId = PrepareAddressSelectL( defaults, techTypeUid );
    CCoeEnv::Static()->CreateResourceReaderLC( resReader, resourceId );

    TPbk2AddressSelectParams params(
        *iStoreContact,
        Phonebook2::Pbk2AppUi()->ApplicationServices().ContactManager(),
        Phonebook2::Pbk2AppUi()->ApplicationServices().NameFormatter(),
        *iFieldPropertyArray,
        resReader );
    params.SetFocusedField( iFocusedField );
    params.SetUseDefaultDirectly( ETrue );
    params.SetDefaultPriorities( defaults );
    params.SetSuppressWarnings( ETrue );

    CPbk2AddressSelect* addressSelect = CPbk2AddressSelect::NewL( params );
    MVPbkStoreContactField* selectedField = addressSelect->ExecuteLD();

    CleanupStack::PopAndDestroy( 2 ); // defaults, resReader

    if ( selectedField )
        {
        CleanupDeletePushL( selectedField );
        SetAddressFromFieldL( *selectedField );
        CleanupStack::PopAndDestroy(); // selectedField
        iState = ERetrieving;
        }
    else 
        {
        if ( iPguUIExtensionPlugin->IsEndCallKeyPressed() )
    	       {
    	       iPguUIExtensionPlugin->ClearEndCallKeyPressedFlag();
    	       iState = EStopping;
             }
        else
            {
	          iState = ERetrieving;
            } 
        }          
    IssueRequest();
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::PrepareAddressSelectL
// --------------------------------------------------------------------------
//
inline TInt CPguSendMessageGroupCmd::PrepareAddressSelectL
        ( RVPbkContactFieldDefaultPriorities& aPriorities,
          TUid aTechType )
    {
    // Precondition
    __ASSERT_DEBUG( iMtmUid != KNullUid, Panic( EPanicUnknownMedia) );

    TInt resourceId = KErrNotFound;

    // SMS
    if ( iMtmUid == KSenduiMtmSmsUid ||
         aTechType == KSenduiTechnologySmsUid )
        {
        if ( FeatureManager::FeatureSupported( KFeatureIdEmailOverSms ) )
            {
            resourceId = R_PBK2_EMAIL_OVER_SMS_ADDRESS_SELECT;
            User::LeaveIfError( aPriorities.Append
                ( EVPbkDefaultTypeEmailOverSms ) );
            }
        else
            {
            resourceId = R_PBK2_PHONE_NUMBER_SELECT;
            User::LeaveIfError( aPriorities.Append( EVPbkDefaultTypeSms ) );
            }
        }
    // MMS
    else if ( iMtmUid == KSenduiMtmMmsUid ||
              aTechType == KSenduiTechnologyMmsUid )
        {
        resourceId = R_PBK2_MMS_ADDRESS_SELECT;
        User::LeaveIfError( aPriorities.Append( EVPbkDefaultTypeMms ) );
        }
    // E-mail
    else if ( iMtmUid ==  KSenduiMtmSmtpUid ||
              aTechType == KSenduiTechnologyMailUid )
        {
        resourceId = R_PBK2_EMAIL_ADDRESS_SELECT;
        User::LeaveIfError( aPriorities.Append( EVPbkDefaultTypeEmail ) );
        }
    // Unified message
    else if ( iMtmUid == KSenduiMtmUniMessageUid )
        {
        if ( FeatureManager::FeatureSupported( KFeatureIdMMS ) )
            {
            if (Phonebook2::Pbk2AppUi()->ApplicationServices().
                LocallyVariatedFeatureEnabled( EVPbkLVShowEmailInSendMsg ))
            {
                resourceId = R_PBK2_UNIFIED_EDITOR_MMS_ADDRESS_SELECT;
            }
            else
            {
                resourceId = R_PBK2_UNIFIED_EDITOR_PHONE_NUMBER_SELECT;
            }
            User::LeaveIfError( aPriorities.Append( EVPbkDefaultTypeMms ) );
            }

        if ( FeatureManager::FeatureSupported
                ( KFeatureIdEmailOverSms ) )
            {
            if ( resourceId == KErrNotFound )
                {
                resourceId =
                    R_PBK2_UNIFIED_EDITOR_EMAIL_OVER_SMS_ADDRESS_SELECT;
                }
            // Include SMS default always in unified message,
            // in addition it has MMS default included with higher priority
            User::LeaveIfError( aPriorities.Append(
                EVPbkDefaultTypeEmailOverSms ) );
            }
        else
            {
            if ( resourceId == KErrNotFound )
                {
                resourceId = R_PBK2_UNIFIED_EDITOR_PHONE_NUMBER_SELECT;
                }
            // Include SMS default always in unified message,
            // in addition it has MMS default included with higher priority
            User::LeaveIfError( aPriorities.Append( EVPbkDefaultTypeSms ) );
            }
        }

    // Postcondition
    __ASSERT_DEBUG( resourceId != KErrNotFound, Panic( EPanicLogic) );

    return resourceId;
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::SetAddressFromFieldL
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::SetAddressFromFieldL(
        MVPbkStoreContactField& aField )
    {
    HBufC* address = MVPbkContactFieldTextData::Cast( aField.FieldData() ).
        Text().AllocL();
    CleanupStack::PushL( address );

    if ( address && address->Des().Length() > 0 )
        {
        HBufC* nameBuffer =
            Phonebook2::Pbk2AppUi()->ApplicationServices().NameFormatter().
                GetContactTitleOrNullL(
                    static_cast<const MVPbkBaseContactFieldCollection&>(
                        iStoreContact->Fields() ),
                        KDefaultTitleFormat );
        if ( nameBuffer )
            {
            CleanupStack::PushL( nameBuffer );
            iMessageData->AppendToAddressL( *address, *nameBuffer );
            CleanupStack::PopAndDestroy( nameBuffer );
            }
        else
            {
            iMessageData->AppendToAddressL( *address );
            }
        }
    CleanupStack::PopAndDestroy( address );
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::ProcessDismissed
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::ProcessDismissed( TInt /*aCancelCode*/ )
    {
    if (iUiControl)
        {
        iUiControl->UpdateAfterCommandExecution();
        }

    // Notify command owner that the command has finished
    if ( iCommandObserver )
        {
        iCommandObserver->CommandFinished( *this );
        }
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::FilterErrors
// --------------------------------------------------------------------------
//
TInt CPguSendMessageGroupCmd::FilterErrors( TInt aErrorCode )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPguSendMessageGroupCmd::FilterErrors(%d) start"), aErrorCode);

    TInt result = aErrorCode;
    switch ( aErrorCode )
        {
        case KErrNotFound:  // FALLTHROUGH
        case KErrInUse:
            {
            // Ignore these errors
            // KErrNotFound means that somebody got the contact first
            // KErrInUse means that the contact is open
            result = KErrNone;
            break;
            }
        default:  // Something more serious happened -> give up
            {
            Cancel();
            ProcessDismissed( aErrorCode );
            break;
            }
        }

    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPguSendMessageGroupCmd::FilterErrors(%d) end"), result );

    return result;
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::IssueRequest
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::IssueRequest()
    {
    if ( !IsActive() )
        {
        TRequestStatus* status = &iStatus;
        User::RequestComplete( status, KErrNone );
        SetActive();
        }
    }

// --------------------------------------------------------------------------
// CPguSendMessageGroupCmd::IssueStopRequest
// --------------------------------------------------------------------------
//
void CPguSendMessageGroupCmd::IssueStopRequest()
    {
    iState = EStopping;
    if ( !IsActive() )
        {
        IssueRequest();
        }
    }

//  End of File
