/*
* 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 command handler.
*
*/


// INCLUDE FILES
#include "CPbk2CommandHandler.h"

// Phonebook 2
#include "CPbk2CommandFactory.h"
#include "CPbk2CommandStore.h"
#include "CPbk2AiwInterestArray.h"
#include <MPbk2ViewExplorer.h>
#include <CPbk2AppViewBase.h>
#include <CPbk2AppUiBase.h>
#include <CPbk2UIExtensionManager.h>
#include <MPbk2Command.h>
#include <Pbk2Commands.rsg>
#include <Pbk2UIControls.rsg>
#include <CPbk2ViewState.h>
#include <CPbk2PhonebookInfoDlg.h>
#include <TPbk2StoreContactAnalyzer.h>
#include <MPbk2ContactNameFormatter.h>
#include <CPbk2StoreProperty.h>
#include <CPbk2StorePropertyArray.h>
#include <CPbk2ContactRelocator.h>
#include <MPbk2ContactLinkIterator.h>
#include <CPbk2PresentationContact.h>
#include <CPbk2PresentationContactFieldCollection.h>
#include <CPbk2FieldPropertyArray.h>
#include <cpbk2commandactivator.h>
#include <CPbk2ApplicationServices.h>
#include <MPbk2AppUi.h>

// Virtual Phonebook
#include <CVPbkContactManager.h>
#include <MVPbkStoreContactField.h>
#include <MVPbkStoreContact.h>
#include <MVPbkContactStore.h>
#include <MVPbkContactStoreProperties.h>
#include <MVPbkContactAttributeManager.h>
#include <MVPbkContactLinkArray.h>
#include <MVPbkContactLink.h>
#include <CVPbkSpeedDialAttribute.h>
#include <MVPbkStoreContact.h>
#include <VPbkContactStoreUris.h>

// System includes
#include <avkon.hrh>
#include <eikmenup.h>
#include <featmgr.h>
#include <hlplch.h>
#include <akntoolbar.h>
#include <eikmenub.h>


/// Unnamed namespace for local definitions
namespace {

#ifdef _DEBUG
enum TPanicCode
    {
    EPanicPreCond_CmdOpenMeViewsL = 1,
    EPanicPreCond_CmdOpenSettingsViewL,
    EPanicPreCond_CmdOpenPreviousViewL,
    EPanicPreCond_CmdOpenHelpL,
    EPanicLogic_FocusedFieldMatchesFieldTypeL,
    EPanicLogic_FocusedContactHasFieldTypeL
    };

void Panic(TPanicCode aReason)
    {
    _LIT(KPanicText, "CPbk2CommandHandler");
    User::Panic(KPanicText, aReason);
    }
#endif //_DEBUG

/**
 * Checks if focused field is of given field type.
 *
 * @param aUiControl        UI control.
 * @param aSelectorResId    Selector resource id.
 * @param aContactManager   Virtual Phonebook contact manager.
 * @return  ETrue if field type matches with given types.
 */
TBool FocusedFieldMatchesFieldTypeL(
        MPbk2ContactUiControl& aUiControl,
        TInt aSelectorResId,
        CVPbkContactManager& aContactManager )
    {
    const MVPbkStoreContact* contact = aUiControl.FocusedStoreContact();
    __ASSERT_DEBUG(contact, Panic
            ( EPanicLogic_FocusedFieldMatchesFieldTypeL ) );

    TPbk2StoreContactAnalyzer analyzer( aContactManager, NULL );
    const MVPbkBaseContactField* field = aUiControl.FocusedField();
    return field &&
        analyzer.IsFieldTypeIncludedL( *field, aSelectorResId );
    }

/**
 * Checks if the focused contact have a given field type.
 *
 * @param aUiControl        UI control
 * @param aSelectorResId    Selector resource id.
 * @param aContactManager   Virtual Phonebook contact manager.
 * @return  Index of the field having the type, KErrNotFound if
 *          the contact does not have the field type.
 */
 TInt FocusedContactHasFieldTypeL(
        MPbk2ContactUiControl& aUiControl,
        TInt aSelectorResId,
        CVPbkContactManager& aContactManager )
    {
    TInt ret = KErrNotFound;
    const MVPbkStoreContact* contact = aUiControl.FocusedStoreContact();
    __ASSERT_DEBUG( contact,
        Panic( EPanicLogic_FocusedContactHasFieldTypeL ) );

    TPbk2StoreContactAnalyzer analyzer( aContactManager, contact );
    ret = analyzer.HasFieldL( aSelectorResId );
    return ret;
    }

/**
 * Checks if command is 'exit' command.
 *
 * @param aCommandId    The command to check.
 * @return  ETrue if command is an exit command, EFalse otherwise.
 */
TBool IsExitCommand( TInt aCommandId )
    {
    TBool ret = EFalse;

    if ( EEikCmdExit == aCommandId || EAknSoftkeyExit == aCommandId ||
         EAknCmdExit == aCommandId || EPbk2CmdExit == aCommandId )
        {
        ret = ETrue;
        }

    return ret;
    }

} /// namespace


// --------------------------------------------------------------------------
// CPbk2CommandHandler::CPbk2CommandHandler
// --------------------------------------------------------------------------
//
inline CPbk2CommandHandler::CPbk2CommandHandler()
    {
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::~CPbk2CommandHandler
// --------------------------------------------------------------------------
//
CPbk2CommandHandler::~CPbk2CommandHandler()
    {
    delete iAiwInterestArray;
    delete iCommandStore;
    delete iCommandFactory;
    delete iContactRelocator;
    Release(iExtensionManager);
    Release(iAppServices);
    FeatureManager::UnInitializeLib();
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::NewL
// --------------------------------------------------------------------------
//
EXPORT_C CPbk2CommandHandler* CPbk2CommandHandler::NewL()
    {
    CPbk2CommandHandler* self = new(ELeave) CPbk2CommandHandler();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::ConstructL
// --------------------------------------------------------------------------
//
inline void CPbk2CommandHandler::ConstructL()
    {
    iCommandFactory = CPbk2CommandFactory::NewL();
    iCommandStore = CPbk2CommandStore::NewL();
    iAiwInterestArray = CPbk2AiwInterestArray::NewL();
    iExtensionManager = CPbk2UIExtensionManager::InstanceL();
    iContactRelocator = CPbk2ContactRelocator::NewL();
    iAppServices = CPbk2ApplicationServices::InstanceL();

    // Initialize feature manager
    FeatureManager::InitializeLibL();
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::HandleCommandL
// --------------------------------------------------------------------------
//
TBool CPbk2CommandHandler::HandleCommandL
        ( const TInt aCommandId, MPbk2ContactUiControl& aControl,
          const CPbk2AppViewBase* aAppView )
    {
    TBool ret = ETrue;

    // Exit commands are forwarded right away to appui
    // Otherwise there is possibility that
    // 'exit' command is not handled in low memory situations
    if ( IsExitCommand( aCommandId ) )
        {
        ret = EFalse;
        }

    // Offer the command to AIW unless it is exit command
    if ( ret && !iAiwInterestArray->HandleCommandL
            ( aCommandId, aControl, KNullHandle ) )
        {
        // Try generic command, this can also be a command from an extension
        ret = CmdGenericCommandL( TPbk2CommandId( aCommandId ), aControl );
        if ( !ret )
            {
            ret = ETrue;
            switch ( aCommandId )
                {
                case EAknSoftkeyBack:               // FALLTHROUGH
                case EPbk2CmdOpenPreviousView:
                    {
                    CmdOpenPreviousViewL( aControl, aAppView );
                    break;
                    }
                case EPbk2CmdSettings:
                    {
                    CmdOpenSettingsViewL( aControl, aAppView,
                        Phonebook2::KPbk2SettingsViewUid );
                    break;
                    }
                case EAknCmdHelp:
                    {
                    CmdOpenHelpL( aControl, aAppView );
                    break;
                    }
                default:
                    {
                    ret = EFalse;
                    break;
                    }
                }
            }
        }
    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::DynInitMenuPaneL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::DynInitMenuPaneL(
        TInt aResourceId,
        CEikMenuPane* aMenuPane,
        CPbk2AppViewBase& aViewBase,
        MPbk2ContactUiControl& aControl )
    {
    // First, delegate to AIW interests.
    // If the menu initialization is handled there,
    // there's no need to continue here
    if ( !iAiwInterestArray->DynInitMenuPaneL
            ( aResourceId, *aMenuPane, aControl ) )
        {
        // Then call extensions
        iExtensionManager->DynInitMenuPaneL( aResourceId, aMenuPane,
            aViewBase, aControl );

        // First perform standard menu filtering
        PerformStandardMenuFilteringL( aResourceId, aMenuPane, aControl );

        // Then perform field type based filtering
        PerformFieldTypeBasedFilteringL( aResourceId, aMenuPane, aControl );

        // Finally perform store specific filtering
        PerformStoreSpecificFilteringL( aResourceId, aMenuPane, aControl );
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::RegisterAiwInterestL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::RegisterAiwInterestL(
        const TInt aInterestId,
        const TInt aMenuResourceId,
        const TInt aInterestResourceId,
        const TBool aAttachBaseService)
    {
    iAiwInterestArray->QueueInterestL(aInterestId,
        aMenuResourceId, aInterestResourceId, aAttachBaseService);
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::ServiceCmdByMenuCmd
// --------------------------------------------------------------------------
//
TInt CPbk2CommandHandler::ServiceCmdByMenuCmd(
        TInt aMenuCmdId ) const
    {
    return iAiwInterestArray->ServiceCmdByMenuCmd( aMenuCmdId );
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::AddAndExecuteCommandL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::AddAndExecuteCommandL(
        MPbk2Command* aCommand)
    {
    iCommandStore->AddAndExecuteCommandL(aCommand);
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::AddMenuCommandObserver
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::AddMenuCommandObserver(
        MPbk2MenuCommandObserver& aObserver)
    {
    iCommandStore->AddMenuCommandObserver(aObserver);
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::RemoveMenuCommandObserver
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::RemoveMenuCommandObserver(
        MPbk2MenuCommandObserver& aObserver)
    {
    iCommandStore->RemoveMenuCommandObserver(aObserver);
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::DynInitToolbarL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::DynInitToolbarL
        ( TInt aResourceId, CAknToolbar* aToolbar,
          const CPbk2AppViewBase& /*aAppView*/,
          MPbk2ContactUiControl& aControl )
    {
    switch ( aResourceId )
        {
        case R_PBK2_NAMESLIST_TOOLBAR:
            {
            if ( aControl.FocusedContactIndex() == KErrNotFound )
                {
                // If there is not focused contact (empty list or otherwise no
                // focus) then disable calling and message writing
                aToolbar->SetItemDimmed( EPbk2CmdCall, ETrue, ETrue );
                aToolbar->SetItemDimmed( EPbk2CmdWriteNoQuery, ETrue, ETrue );
                }
            else if ( aControl.ContactsMarked() )
                {
                // Disable calling to many contacts
                aToolbar->SetItemDimmed( EPbk2CmdCall, ETrue, ETrue );
                }
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::OfferToolbarEventL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::OfferToolbarEventL
        ( TInt aCommand, MPbk2ContactUiControl& aControl,
          const CPbk2AppViewBase* aAppView )
    {
    if ( aAppView )
        {
    HandleCommandL( aCommand, aControl, aAppView );
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::CmdOpenSettingsViewL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::CmdOpenSettingsViewL
        ( MPbk2ContactUiControl& aControl,
          const CPbk2AppViewBase* aAppView, TUid aViewId )
    {
    if (aAppView)
        {
        // Phonebook 2 view explorer for view switching
        MPbk2ViewExplorer* viewExplorer = Phonebook2::Pbk2AppUi()->Pbk2ViewExplorer();

        __ASSERT_DEBUG( viewExplorer,
            Panic( EPanicPreCond_CmdOpenSettingsViewL ) );

        CPbk2ViewState* state = aAppView->ViewStateLC();
        viewExplorer->ActivatePhonebook2ViewL
            ( aViewId, state );
        CleanupStack::PopAndDestroy( state );
        aControl.UpdateAfterCommandExecution();
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::CmdOpenPreviousViewL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::CmdOpenPreviousViewL
        ( MPbk2ContactUiControl& /*aControl*/,
          const CPbk2AppViewBase* aAppView )
    {
    if (aAppView)
        {
        // Phonebook 2 view explorer for view switching
        MPbk2ViewExplorer* viewExplorer = Phonebook2::Pbk2AppUi()->Pbk2ViewExplorer();

        CPbk2ViewState* state = aAppView->ViewStateLC();
        viewExplorer->ActivatePreviousViewL( state );
        CleanupStack::PopAndDestroy( state );
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::CmdOpenHelpL
// --------------------------------------------------------------------------
//
void CPbk2CommandHandler::CmdOpenHelpL
        ( MPbk2ContactUiControl& aControl,
          const CPbk2AppViewBase* aAppView )
    {
    if ( aAppView )
        {
    TCoeHelpContext helpContext;
    if ( iExtensionManager->GetHelpContextL
            ( helpContext, *aAppView, aControl) )
        {
        CArrayFix<TCoeHelpContext>* helpContextArray =
                new (ELeave) CArrayFixFlat<TCoeHelpContext>( 1 );
        CleanupStack::PushL( helpContextArray );
        helpContextArray->AppendL( helpContext );

        // HlpLauncher destroys the help context array
        CleanupStack::Pop( helpContextArray );
        HlpLauncher::LaunchHelpApplicationL
            ( CCoeEnv::Static()->WsSession(), helpContextArray );
        }
    else
        {
        HlpLauncher::LaunchHelpApplicationL
            ( CCoeEnv::Static()->WsSession(),
              CEikonEnv::Static()->EikAppUi()->AppHelpContextL() );
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::CmdGenericCommandL
// --------------------------------------------------------------------------
//
TBool CPbk2CommandHandler::CmdGenericCommandL(
        TPbk2CommandId aCommandId,
        MPbk2ContactUiControl& aControl)
    {
    // Create the command object
    TBool result = EFalse;
    MPbk2Command* cmd = iCommandFactory->CreateCommandForIdL(
            aCommandId, aControl);
    if (cmd)
        {
        // If command factory was able to create the command,
        // add it to the command store and execute it
        iCommandStore->AddAndExecuteCommandL(cmd);
        result = ETrue;
        }
    return result;
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::PerformStandardMenuFilteringL
// --------------------------------------------------------------------------
//
inline void CPbk2CommandHandler::PerformStandardMenuFilteringL(
        TInt aResourceId,
        CEikMenuPane* aMenuPane,
        MPbk2ContactUiControl& aControl )
    {
    switch (aResourceId)
        {
        case R_PHONEBOOK2_NAMESLIST_DELETE_MENU:
            {
            if ( aControl.NumberOfContacts() == 0 )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdDeleteMe, ETrue );
                }
            if ( aControl.ContactsMarked() )
                {
                aMenuPane->SetItemSpecific( EPbk2CmdDeleteMe, EFalse );
                }
            break;
            }

        case R_PHONEBOOK2_NAMELIST_CALL_CONTACT_MENU:
            {
            // Weed out commands not meant to be used with marked items
            if ( aControl.ContactsMarked() )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdCall, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_NAMESLIST_CREATE_MENU:
            {
            // Weed out commands not meant to be used with marked items
            if ( aControl.ContactsMarked() )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdCreateNew, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_NAMESLIST_SEND_URL_MENU:
            {
            // Weed out commands not meant to be used with empty list
            if ( aControl.NumberOfContacts() == 0 )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdGoToURL, ETrue );
                }

            if ( aControl.ContactsMarked() )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdSend, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdGoToURL, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_NAMESLIST_COPY_MENU:          // FALLTHROUGH
        case R_PHONEBOOK2_NAMESLIST_COPY_CONTEXT_MENU:
            {
            // The copy menu is not shown if there are no contacts
            TBool itemSpecCommEnabled = Phonebook2::Pbk2AppUi()->ActiveView()->MenuBar()->ItemSpecificCommandsEnabled();
            if ( aControl.NumberOfContacts() == 0 || 
                    ( !aControl.ContactsMarked() && !itemSpecCommEnabled ) ||
                    ( !aControl.FocusedContactL() && itemSpecCommEnabled && 
                            !aControl.ContactsMarked() ) )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdCopy, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_EDIT_MENU:
            {
            // Weed out commands not meant to be used with empty contact
            if ( aControl.NumberOfContactFields() == 0 )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdWrite, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdGoToURL, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdDefaultSettings, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_EXTENDED_MENU:
            {
            CVPbkContactManager& manager = iAppServices->ContactManager();

            // Always dim thumbnail if image/text supported or vice versa
            if ( FeatureManager::FeatureSupported
                    ( KFeatureIdCallImagetext ) )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdFetchThumbnail, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdRemoveThumbnail, ETrue );
                }
            else
                {
                aMenuPane->SetItemDimmed( EPbk2CmdAddImage, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdImage, ETrue );
                }

            // Weed out commands not meant to be used with empty contact
            if ( aControl.NumberOfContactFields() == 0 )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdSend, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdAssignSpeedDial, ETrue);
                aMenuPane->SetItemDimmed( EPbk2CmdRemoveSpeedDial, ETrue );
                aMenuPane->SetItemDimmed
                    ( EPbk2CmdPersonalRingingTone, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdCopy, ETrue );

                if ( !FeatureManager::FeatureSupported
                        ( KFeatureIdCallImagetext ) )
                    {
                    aMenuPane->SetItemDimmed
                        ( EPbk2CmdFetchThumbnail, ETrue );
                    aMenuPane->SetItemDimmed
                        ( EPbk2CmdRemoveThumbnail, ETrue );
                    }
                else
                    {
                    aMenuPane->SetItemDimmed( EPbk2CmdAddImage, ETrue );
                    aMenuPane->SetItemDimmed( EPbk2CmdImage, ETrue );
                    }
                }
            else
                {
                // Utilise attribute manager to find out if
                // the contact have a speed dial defined
                TBool hasSpeedDial = HasSpeedDialL( aControl );

                // Filtering is based on the speed dial existence
                if ( !hasSpeedDial )
                    {
                    aMenuPane->SetItemDimmed
                        ( EPbk2CmdRemoveSpeedDial, ETrue );
                    }
                else
                    {
                    aMenuPane->SetItemDimmed
                        ( EPbk2CmdAssignSpeedDial, ETrue );
                    }
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_CONTEXT_MENU:
            {
            // Weed out commands not meant to be used with empty contact
            if ( aControl.NumberOfContactFields() == 0 )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdWrite, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdGoToURL, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdPersonalRingingTone, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdUseNumber, ETrue );
                aMenuPane->SetItemDimmed( EPbk2CmdImage, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_INFO_MENU:
            {
            // Filter memory info items when list box is empty
            // or items are marked
            if ( aControl.NumberOfContacts() == 0 ||
                 aControl.ContactsMarked() )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdPhonebook2Info, ETrue );
                }
            break;
            }

        case R_PHONEBOOK2_SYSTEM_MENU:
            {
            if ( !FeatureManager::FeatureSupported( KFeatureIdHelp ) )
                {
                // Remove non-supported help from menu
                aMenuPane->SetItemDimmed( EAknCmdHelp, ETrue );
                }
            break;
            }
        case R_PHONEBOOK2_MERGE_CONTACTS:
            {
            TBool supported = FeatureManager::FeatureSupported( KFeatureIdFfContactsMerge );
                       
            if ( !supported || aControl.ContactsMarked() )
                {
                aMenuPane->SetItemDimmed( EPbk2CmdMergeContacts, ETrue );
                }
            break;
            }
        default:
            {
            // Do nothing
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::PerformStoreSpecificFiltering
// --------------------------------------------------------------------------
//
inline void CPbk2CommandHandler::PerformStoreSpecificFilteringL(
            TInt aResourceId,
            CEikMenuPane* aMenuPane,
            MPbk2ContactUiControl& aControl )
    {
    // ETrue if all selected contacts are read-only
    TBool readOnly = AreSelectedContactsFromReadOnlyStoreL( aControl );

    switch (aResourceId)
        {
        case R_PHONEBOOK2_NAMESLIST_CONTEXT_MENU_MARKED_ITEMS: // FALLTHROUGH
        case R_PHONEBOOK2_NAMESLIST_DELETE_MENU:
            {
            // Weed out commands not meant to be used with read only stores
            if (readOnly)
                {
                aMenuPane->SetItemDimmed(EPbk2CmdDeleteMe, ETrue);
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_EDIT_MENU:
            {
            TBool phoneMemoryInConfiguration =
                    iContactRelocator->IsPhoneMemoryInConfigurationL();

            // Weed out commands not meant to be used with read only stores
            if (readOnly)
                {
                aMenuPane->SetItemDimmed(EPbk2CmdDeleteMe, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdEditMe, ETrue);
                }

            // Weed out phone memory specific commands, if there is no
            // phone memory in configuration
            if (!phoneMemoryInConfiguration)
                {
                aMenuPane->SetItemDimmed(EPbk2CmdDefaultSettings, ETrue);
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_EXTENDED_MENU:
            {
            TBool phoneMemoryInConfiguration =
                    iContactRelocator->IsPhoneMemoryInConfigurationL();

            // Weed out phone memory specific commands, if there is no
            // phone memory in configuration
            if (!phoneMemoryInConfiguration)
                {
                aMenuPane->SetItemDimmed(EPbk2CmdAssignSpeedDial, ETrue);
                if (!FeatureManager::FeatureSupported(KFeatureIdCallImagetext))
                    {
                    aMenuPane->SetItemDimmed(EPbk2CmdFetchThumbnail, ETrue);
                    }
                else
                    {
                    aMenuPane->SetItemDimmed(EPbk2CmdAddImage, ETrue);
                    aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                    }
                aMenuPane->SetItemDimmed(EPbk2CmdPersonalRingingTone, ETrue);
                }

            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_CONTEXT_MENU:
            {
            // Weed out commands not meant to be used with read only stores
            if (readOnly)
                {
                aMenuPane->SetItemDimmed(EPbk2CmdEditMe, ETrue);
                }
            break;
            }
        case R_PHONEBOOK2_MERGE_CONTACTS:
            {
            TBool phoneMemoryInConfiguration =
                    iContactRelocator->IsPhoneMemoryInConfigurationL();
            
            if( !phoneMemoryInConfiguration ) 
                {
                aMenuPane->SetItemDimmed( EPbk2CmdMergeContacts, ETrue );
                }
            break;
            }
        default:
            {
            // Do nothing
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::PerformFieldTypeBasedFilteringL
// --------------------------------------------------------------------------
//
inline void CPbk2CommandHandler::PerformFieldTypeBasedFilteringL(
            TInt aResourceId,
            CEikMenuPane* aMenuPane,
            MPbk2ContactUiControl& aControl )
    {
    CVPbkContactManager& manager = iAppServices->ContactManager();

    switch (aResourceId)
        {
        case R_PHONEBOOK2_CONTACTINFO_EDIT_MENU:
            {
            // Weed out commands which are not shown if currently focused field is
            // not phone number
            if (!FocusedFieldMatchesFieldTypeL(aControl,
                    R_PHONEBOOK2_PHONENUMBER_SELECTOR, manager))
                {
                aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue);
                }

            // If the contact does not have URL field, there is no
            // "Go To URL" option available
            if (FocusedContactHasFieldTypeL(aControl,
                    R_PHONEBOOK2_URL_SELECTOR, manager) < 0)
                {
                aMenuPane->SetItemDimmed(EPbk2CmdGoToURL, ETrue);
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_EXTENDED_MENU:
            {
            // Speed dial menus are variated based on VoIP support
            if( FeatureManager::FeatureSupported( KFeatureIdCommonVoip ) )
                {
                // Weed out commands which are not shown if currently focused field is
                // neither phone number nor VoIP field
                if( !FocusedFieldMatchesFieldTypeL( aControl,
                        R_PHONEBOOK2_SIP_MSISDN_SELECTOR, manager ) )
                    {
                    aMenuPane->SetItemDimmed( EPbk2CmdAssignSpeedDial, ETrue );
                    aMenuPane->SetItemDimmed( EPbk2CmdRemoveSpeedDial, ETrue );
                    }
                }
            else
                {
                // Weed out commands which are not shown if currently focused field is
                // not phone number
                if( !FocusedFieldMatchesFieldTypeL( aControl,
                        R_PHONEBOOK2_PHONENUMBER_SELECTOR, manager ) )
                    {
                    aMenuPane->SetItemDimmed( EPbk2CmdAssignSpeedDial, ETrue );
                    aMenuPane->SetItemDimmed( EPbk2CmdRemoveSpeedDial, ETrue );
                    }
                }

            // Alternate Thumbnail/Call object menus based on whether data
            // has been added or not
            if (!FeatureManager::FeatureSupported(KFeatureIdCallImagetext))
                {
                // Weed out command Remove Thumbnail if contact does not have one
                if (FocusedContactHasFieldTypeL(aControl,
                        R_PHONEBOOK2_THUMBNAIL_SELECTOR, manager) < 0)
                    {
                    aMenuPane->SetItemDimmed(EPbk2CmdRemoveThumbnail, ETrue);
                    }
                }
            else
                {
                if ((FocusedContactHasFieldTypeL(aControl,
                        R_PHONEBOOK2_IMAGE_SELECTOR, manager) < 0) &&
                    (FocusedContactHasFieldTypeL(aControl,
                        R_PHONEBOOK2_THUMBNAIL_SELECTOR, manager) < 0))
                    {
                    // Weed out Image submenu if contact does not have image
                    aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                    }
                else
                    {
                    // Weed out command Add Image if contact already has one
                    aMenuPane->SetItemDimmed(EPbk2CmdAddImage, ETrue);
                    }
                }
            break;
            }

        case R_PHONEBOOK2_CONTACTINFO_CONTEXT_MENU:
            {
            TBool filtered = EFalse;

            // Telephone field
            if (FocusedFieldMatchesFieldTypeL(aControl,
                    R_PHONEBOOK2_PHONENUMBER_SELECTOR, manager))
                {
                aMenuPane->SetItemDimmed(EPbk2CmdGoToURL, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdPersonalRingingTone, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                filtered = ETrue;

                // Further filtering of phone number fields
                // Pager field
                // Pager returns a match for R_PHONEBOOK2_PHONENUMBER_SELECTOR
                // too, but it requires further filtering, which is handled here
                if (FocusedFieldMatchesFieldTypeL(aControl,
                        R_PHONEBOOK2_PAGER_SELECTOR, manager))
                    {
                    aMenuPane->SetItemDimmed(EPbk2CmdWrite, ETrue);
                    aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                    }

                // VoIP
                // VoIP returns a match for R_PHONEBOOK2_PHONENUMBER_SELECTOR
                // too, but it requires further filtering, which is handled here
                if (FocusedFieldMatchesFieldTypeL(aControl,
                        R_PHONEBOOK2_VOIP_SELECTOR, manager))
                    {
                    aMenuPane->SetItemDimmed(EPbk2CmdWrite, ETrue);
                    aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                    }
                } // further filtering

            // Email field
            if (FocusedFieldMatchesFieldTypeL(aControl,
                    R_PHONEBOOK2_EMAIL_SELECTOR, manager))
                {
                aMenuPane->SetItemDimmed(EPbk2CmdGoToURL, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                aMenuPane->SetItemDimmed(EPbk2CmdPersonalRingingTone, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                filtered = ETrue;
                }

            // URL field
            if (FocusedFieldMatchesFieldTypeL(aControl,
                    R_PHONEBOOK2_URL_SELECTOR, manager))
                {
                aMenuPane->SetItemDimmed(EPbk2CmdWrite, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                aMenuPane->SetItemDimmed(EPbk2CmdPersonalRingingTone, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                filtered = ETrue;
                }

            // Ringing tone field
            if (FocusedFieldMatchesFieldTypeL(aControl,
                    R_PHONEBOOK2_RINGTONE_SELECTOR, manager))
                {
                aMenuPane->SetItemDimmed(EPbk2CmdWrite, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdGoToURL, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdEditMe, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                filtered = ETrue;
                }

            // Image/text context submenus
            if( FocusedFieldMatchesFieldTypeL(aControl,
                    R_PHONEBOOK2_IMAGE_SELECTOR, manager))
                {
                aMenuPane->SetItemDimmed(EPbk2CmdWrite, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdGoToURL, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                aMenuPane->SetItemDimmed(EPbk2CmdPersonalRingingTone, ETrue);
                filtered = ETrue;
                }

            if (!filtered)
                {
                // Default filtering leaves only edit option in the menu
                aMenuPane->SetItemDimmed(EPbk2CmdWrite, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdGoToURL, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdUseNumber, ETrue );
                aMenuPane->SetItemDimmed(EPbk2CmdPersonalRingingTone, ETrue);
                aMenuPane->SetItemDimmed(EPbk2CmdImage, ETrue);
                }
            break;
            }

        case R_PHONEBOOK2_IMAGE_SUBMENU:
            {
            if (FeatureManager::FeatureSupported(KFeatureIdCallImagetext))
                {
                if (FocusedContactHasFieldTypeL(aControl,
                        R_PHONEBOOK2_IMAGE_SELECTOR, manager) < 0)
                    {
                    // Weed out Image View command if contact has no image
                    // (it might have thumbnail from e.g. business card and
                    // and thus other image submenu options)
                    aMenuPane->SetItemDimmed(EPbk2CmdViewImage, ETrue);
                    }
                }
            break;
            }

        default:
            {
            // AIW provider menus are filtered in the corresponding
            // interest item, for example R_PHONEBOOK2_CALL_CONTEXT_MENU
            // is filtered in CPbk2AiwInterestItemCall
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::AreSelectedContactsFromReadOnlyStoreL
// Returns ETrue if all selected contacts are read-only.
// --------------------------------------------------------------------------
//
inline TBool CPbk2CommandHandler::AreSelectedContactsFromReadOnlyStoreL(
            MPbk2ContactUiControl& aControl)
    {
    // Default behavior is that selection is read-only, e.g
    // a link can not be created for folding contact in which case
    // the folding contact cannot be destroyed
    TBool ret = ETrue;

    MPbk2ContactLinkIterator* iterator =
        aControl.SelectedContactsIteratorL();
    if ( iterator )
        {
        CleanupDeletePushL( iterator );

        while( iterator->HasNext() && ret )
            {
            MVPbkContactLink* link = iterator->NextL();

            if ( link && !IsFromReadOnlyStore( *link ) )
                {
                ret = EFalse;
                }

            delete link;
            link = NULL;
            }

        CleanupStack::PopAndDestroy(); // iterator
        }
    else
        {
        // There was no iterator so there are no selected contacts,
        // this means we are operating with the focused contact
        const MVPbkBaseContact* focusedContact =
            aControl.FocusedContactL();
        if ( focusedContact )
            {
            MVPbkContactLink* link = focusedContact->CreateLinkLC();
            if ( link && !IsFromReadOnlyStore( *link ) )
                {
                ret = EFalse;
                }
            CleanupStack::PopAndDestroy(); // link
            }
        }

    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::IsFromReadOnlyStore
// --------------------------------------------------------------------------
//
TBool CPbk2CommandHandler::IsFromReadOnlyStore(
        const MVPbkContactLink& aContactLink ) const
    {
    TBool ret = EFalse;

    const MVPbkContactStore& store = aContactLink.ContactStore();
    if ( store.StoreProperties().ReadOnly() )
        {
        ret = ETrue;
        }

    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::HasSpeedDialL
// --------------------------------------------------------------------------
//
TBool CPbk2CommandHandler::HasSpeedDialL(
        MPbk2ContactUiControl& aControl )
    {
    TBool hasAttribute(EFalse);

    const MVPbkStoreContact* storeContact =
            aControl.FocusedStoreContact();

    // Convert presentation index to store index.
    TInt index( ToStoreFieldIndexL(
                    aControl.FocusedFieldIndex(),
                    storeContact ) );

    if ( index != KErrNotFound )
        {
        const MVPbkStoreContactField& field =
            storeContact->Fields().FieldAt( index );


        hasAttribute =
            iAppServices->ContactManager().ContactAttributeManagerL().
            HasFieldAttributeL(
                CVPbkSpeedDialAttribute::Uid(),
                field );
        }
    return hasAttribute;
    }

// --------------------------------------------------------------------------
// CPbk2CommandHandler::ToStoreFieldIndexL
// --------------------------------------------------------------------------
//
TInt CPbk2CommandHandler::ToStoreFieldIndexL(
        TInt aPresIndex,
        const MVPbkStoreContact* aStoreContact )
    {
    // It is ok to remove const, we don't make any changes
    MVPbkStoreContact* storeContact =
        const_cast<MVPbkStoreContact*>( aStoreContact );

    TInt index( KErrNotFound );
    if ( aPresIndex >= 0 )
        {
        CPbk2PresentationContact* presentationContact =
            CPbk2PresentationContact::NewL(
                *storeContact,
                iAppServices->FieldProperties() );
        CleanupStack::PushL( presentationContact );

        index = presentationContact->PresentationFields().
                    StoreIndexOfField( aPresIndex );

        CleanupStack::PopAndDestroy( presentationContact );
        }
    return index;
    }

// End of File
