/*
* Copyright (c) 2002 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: 
*          Provides Groups list View controller methods
*
*/


// INCLUDE FILES
#include "CPbkGroupsListAppView.h"  // This class' declaration

// System APIs
#include <pbkconfig.hrh>
#include <eikmenup.h>        // CEikMenuPane
#include <cntitem.h>         // CContactGroup
#include <StringLoader.h>

// Phonebook.app APIs
#include <Phonebook.rsg>  // Phonebook resources
#include <pbkdebug.h>
#include "CPbkAppUi.h"
#include <CPbkControlContainer.h>
#include "CPbkSetToneToGroupCmd.h"
#include "CPbkMenuFiltering.h"
#include "CPbkDocument.h"
#include "CPbkAppGlobals.h"

// PbkEng.dll APIs
#include <CPbkConstants.h>
#include <CPbkContactEngine.h>
#include <PbkCommandHandler.h>
#include <CPbkAiwInterestArray.h>

// PbkView.dll APIs
#include <PbkView.rsg>                   // PbkView dll resources
#include <CPbkViewState.h>               // Phonebook view state object
#include <CPbkContactViewListControl.h>
#include <CPbkGroupNameQueryDlg.h>       // CPbkGroupNameQueryDlg
#include <CPbkRingingToneFetch.h>
#include <CPbkPhonebookInfoDlg.h>

// PbkUi.dll APIs
#include <MPbkCommand.h>
#include <MPbkCommandFactory.h>
#include <MenuFilteringFlags.h>

// PbkExtension classes
#include <CPbkExtGlobals.h>
#include <MPbkExtensionFactory.h>
#include <MPbkViewExtension.h>
#include <cshelp/phob.hlp.hrh>

#include <AiwCommon.hrh>            // AIW

// Debugging headers
#include <pbkdebug.h>
#include "PbkProfiling.h"

// From SendUI
#include <SendUiConsts.h>           // Postcard Uid


/// Unnamed namespace for local definitions
namespace {

#ifdef _DEBUG
enum TPanicCode
    {
    EPanicPostCond_DoActivateL = 1,
    EPanicPostCond_DoDeactivate,
    EPanicPreCond_HandleCommandL,
    EPanicPreCond_ConstructL,
    EPanicPostCond_ConstructL,
    EPanicPreCond_CmdOpenGroupL,
    EPanicPreCond_CmdRemoveGroupL,
    EPanicPreCond_CmdRenameGroupL,
    EPanicPreCond_HandleContactViewListControlEventL,
    EPanicPreCond_DynInitMenuPaneL
    };
#endif


// ==================== LOCAL FUNCTIONS ====================

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

}  // namespace


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

inline CPbkGroupsListAppView::CPbkGroupsListAppView() :
        iGroupToFocus(KNullContactId)
    {
    }

inline void CPbkGroupsListAppView::ConstructL()
    {
    // PreCond
     __ASSERT_DEBUG(!iContainer && !iControlState, Panic(EPanicPreCond_ConstructL));

    // Init base class
    __PBK_PROFILE_START(PbkProfiling::EViewBaseConstruct);
    BaseConstructL(R_PHONEBOOK_GROUPSLIST_APPVIEW);
    __PBK_PROFILE_END(PbkProfiling::EViewBaseConstruct);

    iExtGlobal = CPbkExtGlobals::InstanceL();
    
    // Create AIW interest array
    CreateInterestItemAndAttachL(KAiwCmdPoC,
        R_PHONEBOOK_POC_MENU, R_PHONEBOOK_POCUI_AIW_INTEREST, ETrue);

    // PostCond
     __ASSERT_DEBUG(!iContainer && !iControlState, Panic(EPanicPostCond_ConstructL));
    }

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

CPbkGroupsListAppView::~CPbkGroupsListAppView()
    {
    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkGroupsListAppView(%x)::~CPbkGroupsListAppView()"), this);

    delete iContainer;
    delete iParamState;
    delete iControlState;
    Release(iViewExtension);
    Release(iExtGlobal);
    }

void CPbkGroupsListAppView::CmdOpenGroupL()
    {
    //PreCond:
    __ASSERT_DEBUG(iContainer->Control()->NumberOfItems() > 0, Panic(EPanicPreCond_CmdOpenGroupL));

    CPbkViewState* state = iContainer->Control()->GetStateLC();
    PbkAppUi()->ActivatePhonebookViewL(CPbkAppUi::KPbkGroupMembersListViewUid, state);
    CleanupStack::PopAndDestroy();  // state
    }

inline void CPbkGroupsListAppView::CmdWriteToGroupL()
    {
    const TInt selIndex = iContainer->Control()->FocusedContactIdL();
    if (selIndex >= 0)
        {
        CContactGroup* contactGroup = Engine()->ReadContactGroupL( selIndex );
        CleanupStack::PushL( contactGroup );

        TPbkSendingParams params = CreateWriteParamsLC();

		// Create the write message command object
		MPbkCommand* cmd = CPbkAppGlobalsBase::InstanceL()->
			CommandFactory().CreateSendMultipleMessageCmdL(
			*Engine(), 
			params,
			*contactGroup->ItemsContained(),
			NULL, 
			ETrue );
		// Execute the command
		cmd->ExecuteLD();
        CleanupStack::PopAndDestroy(); // params.iMtmFilter
		CleanupStack::PopAndDestroy( contactGroup );
        }
    }

void CPbkGroupsListAppView::CmdCreateNewGroupL()
    {
    HBufC* textBuf = HBufC::NewLC(CPbkConstants::GroupLabelLength());
    TPtr text = textBuf->Des();

    CPbkGroupNameQueryDlg* dlg = CPbkGroupNameQueryDlg::NewL(text, *Engine());
    dlg->SetMaxLength(CPbkConstants::GroupLabelLength());
    if (dlg->ExecuteLD(R_PHONEBOOK_GROUPLIST_NEWGROUP_QUERY))
        {
        // insert new group into database
        CContactGroup* group = Engine()->CreateContactGroupL(text, ETrue);
        iGroupToFocus = group->Id();
        delete group;
        }
    CleanupStack::PopAndDestroy(textBuf);
    }

void CPbkGroupsListAppView::CmdRemoveGroupL()
    {
    //PreCond:
    __ASSERT_DEBUG(iContainer->Control()->NumberOfItems() > 0, 
        Panic(EPanicPreCond_CmdRemoveGroupL));

    // get the focused this index and delete the contact group.
    const TContactItemId groupId = iContainer->Control()->FocusedContactIdL();
    if (groupId != KNullContactId)
        {
        CContactGroup* group = NULL;
        TRAPD(err, group = Engine()->ReadContactGroupL(groupId))
        if (err == KErrNotFound)
            {
            // Ignore KErrNotFound which means that somebody got
            // the contact first
            return;
            }
        User::LeaveIfError(err);
        CleanupStack::PushL(group);
        const CContactIdArray* groupContainsIds = group->ItemsContained();
        HBufC* prompt = NULL;
        if (!groupContainsIds || groupContainsIds->Count()==0)
            {
            // Empty group
            prompt = StringLoader::LoadL(R_QTN_QUERY_COMMON_CONF_DELETE, group->GetGroupLabelL());
            }
        else
            {
            // Nonempty group
            prompt = iCoeEnv->AllocReadResourceL(R_QTN_FLDR_DEL_FULL_GROUPS_QUERY);
            }
        CleanupStack::PopAndDestroy(group);
        CleanupStack::PushL(prompt);
        CAknQueryDialog* dlg = CAknQueryDialog::NewL();
        CleanupStack::PushL(dlg);
        dlg->SetPromptL(*prompt);
        CleanupStack::Pop(); // dlg
        if (dlg->ExecuteLD(R_PBK_GENERAL_CONFIRMATION_QUERY))
            {
            TRAPD(err, Engine()->DeleteContactGroupL(groupId))
            if (err == KErrNotFound)
                {
                // Ignore KErrNotFound which means that
                // somebody got the contact group first
                err = KErrNone;
                }
            User::LeaveIfError(err);
            }
        CleanupStack::PopAndDestroy(); // prompt
        }
    }

void CPbkGroupsListAppView::CmdRenameGroupL()
    {
    //PreCond:
    __ASSERT_DEBUG(iContainer->Control()->NumberOfItems() > 0, 
        Panic(EPanicPreCond_CmdRenameGroupL));

    const TContactItemId groupId = iContainer->Control()->FocusedContactIdL();
    if (groupId != KNullContactId)
        {
        HBufC* textBuf = HBufC::NewLC(CPbkConstants::GroupLabelLength());
        TPtr text = textBuf->Des();

        // get the name of the group into the buffer
        CContactGroup* group = Engine()->OpenContactGroupLCX(groupId);
        text = group->GetGroupLabelL().Left(text.MaxLength());

        CPbkGroupNameQueryDlg* dlg = CPbkGroupNameQueryDlg::NewL(text, *Engine(), EFalse);
        dlg->SetMopParent(this);
        if (dlg->ExecuteLD(R_PHONEBOOK_GROUPLIST_NEWGROUP_QUERY))
            {
            group->SetGroupLabelL(text);
            Engine()->CommitContactGroupL(*group, ETrue);
            iGroupToFocus = groupId;
            }
        CleanupStack::PopAndDestroy(3,textBuf); // group, lock, textBuf
        }
    }

void CPbkGroupsListAppView::CmdSetRingingToneL()
    {
    const TContactItemId groupId = iContainer->Control()->FocusedContactIdL();
    if (groupId != KNullContactId)
        {
        CPbkRingingToneFetch* toneFetch = CPbkRingingToneFetch::NewL(*Engine());
        CleanupStack::PushL(toneFetch);
        TFileName ringingToneFile;
        if (toneFetch->FetchRingingToneL(ringingToneFile))
            {
            CPbkSetToneToGroupCmd* cmd = CPbkSetToneToGroupCmd::NewL
                (*Engine(), groupId, ringingToneFile);
            PbkAppUi()->AddAndExecuteCommandL(cmd);
            }
        CleanupStack::PopAndDestroy(toneFetch);
        }
    }

inline void CPbkGroupsListAppView::CmdOpenSettingsL()
    {
    // Create the settings command object
    MPbkCommand* cmd = CPbkAppGlobalsBase::InstanceL()->
        CommandFactory().CreateSettingsCmdL(*Engine(), *this);
    // Execute the command
    cmd->ExecuteLD();

    // Clear Find box contents and markings
    CPbkContactViewListControl& control = *iContainer->Control();
    control.ResetFindL();
    control.HandleMarkableListUpdateAfterCommandExecution();
    }

inline void CPbkGroupsListAppView::CmdContextMenuL()
    {
    LaunchPopupMenuL(R_PBK_GROUPSLIST_CONTEXT_MENUBAR);
    }

inline void CPbkGroupsListAppView::CmdPhonebookInfoL()
    {
    CPbkContactViewListControl& control = *iContainer->Control();

    // Hide thumbnail
    control.HideThumbnail();
    iContainer->SetFocusing(EFalse);

    // Trap this, so that the thumbnail doesnt get hidden in case of leave
    TRAPD(err, DoShowPhonebookInfoL());

    // Restore
    iContainer->SetFocusing(ETrue);
    control.ShowThumbnailL();

    // In case of an error, leave
    if (err != KErrNone)
        {
        User::Leave(err);
        }
    }
    
inline void CPbkGroupsListAppView::DoShowPhonebookInfoL()
    {
    CPbkPhonebookInfoDlg* infoPopup =
        CPbkPhonebookInfoDlg::NewL(*Engine());
    infoPopup->ExecuteLD();
    }


TBool CPbkGroupsListAppView::HandleCommandKeyL
        (const TKeyEvent& aKeyEvent, 
        TEventCode /*aType*/)
    {
    TBool result = EFalse;
    CPbkContactViewListControl& control = *iContainer->Control();
    if (control.IsReady())
        {
        switch (aKeyEvent.iCode)
            {
            case EKeyOK:
                {
                if (control.NumberOfItems() > 0)
                    {
                    // Select key is mapped to "Open Group" command
                    HandleCommandL(EPbkCmdOpenGroup);
                    result = ETrue;
                    }
                else 
                    {
                    // select key mapped to context sensitive menu if list is empty
                    HandleCommandL(EPbkCmdContextMenu);
                    result = ETrue;
                    }
                break;
                }
            
            case EKeyBackspace:
                {
                if (control.NumberOfItems() > 0)
                    {
                    // Clear key is mapped to Remove Group command if the list
                    // is not empty
                    HandleCommandL(EPbkCmdRemoveGroup);
                    result = ETrue;
                    }
                break;
                }

            default:
                {
                break;
                }
            }
        }

    return result;
    }

CPbkViewState* CPbkGroupsListAppView::GetViewStateLC() const
    {
    return iContainer ? iContainer->Control()->GetStateLC() : NULL;
    }

void CPbkGroupsListAppView::HandleCommandL
        (TInt aCommandId)
    {
    // PreCond: (this is the precond for all Cmd* functions at the same time)
    __ASSERT_DEBUG(iContainer && iViewExtension, Panic(EPanicPreCond_HandleCommandL));
            
    // Offer the command first to AIW
    const TInt focusedContactId = iContainer->Control()->FocusedContactIdL();
    if (focusedContactId != -1)
        {
        CContactGroup* contactGroup = Engine()->ReadContactGroupL(focusedContactId);
        CleanupStack::PushL( contactGroup );
        TInt serviceCmdId = KNullHandle;        
        if (iAiwInterestArray->HandleCommandL(
                aCommandId,
                *contactGroup->ItemsContained(),
                NULL, // no field level focus
                serviceCmdId, this))
            {
            // command handled by AIW
            CleanupStack::PopAndDestroy(); //contactGroup
            return;
            }
        CleanupStack::PopAndDestroy(); //contactGroup
        }

    if (iViewExtension->HandleCommandL(aCommandId/*, *this*/))
        {
        return;
        }

    // Process view-specific commands
    switch (aCommandId) 
        {
        case EPbkCmdOpenGroup:
            {
            CmdOpenGroupL();
            break;
            }

        case EPbkCmdCreateNewGroup:
            {
            PbkAppUi()->FFSClCheckL(PbkCommandHandler(this, 
                &CPbkGroupsListAppView::CmdCreateNewGroupL));
            break;
            }

        case EPbkCmdRemoveGroup:
            {
            CmdRemoveGroupL();
            break;
            }

        case EPbkCmdRenameGroup:
            {
            PbkAppUi()->FFSClCheckL(PbkCommandHandler(this, 
                &CPbkGroupsListAppView::CmdRenameGroupL));
            break;
            }

        case EPbkCmdSetRingingTone:
            {
            PbkAppUi()->FFSClCheckL(PbkCommandHandler(this, 
                &CPbkGroupsListAppView::CmdSetRingingToneL));
            break;
            }

        case EPbkCmdPhonebookInfo:
            {
            CmdPhonebookInfoL();
            break;
            }

        case EPbkCmdContextMenu:
            {
            CmdContextMenuL();
            break;
            }

        case EPbkCmdSettings:
            {
            CmdOpenSettingsL();
            break;
            }
            
        case EPbkCmdWrite:
            {
            PbkAppUi()->FFSClCheckL(PbkCommandHandler(this,
                &CPbkGroupsListAppView::CmdWriteToGroupL ));
            break;
            }

        default:
            {
            // Command not handled here, to app ui.
            AppUi()->HandleCommandL(aCommandId);
            break;
            }
        }
    }

void CPbkGroupsListAppView::DynInitMenuPaneL
        (TInt aResourceId, CEikMenuPane* aMenuPane)
    {
    __ASSERT_DEBUG(iContainer && iViewExtension, 
        Panic(EPanicPreCond_DynInitMenuPaneL));

    iViewExtension->DynInitMenuPaneL(aResourceId, aMenuPane);

    // Set up flags depending on current UI state
    TUint flags = KPbkGroupsView;
    if (iContainer->Control()->NumberOfItems() == 0) 
        {
        flags |= KPbkControlEmpty;
        }
    if (iContainer->Control()->ItemsMarked()) 
        {
        flags |= KPbkItemsMarked;
        }
    if (Engine()->Database().GroupCount() == 0)
        {
        flags |= KPbkNoGroups;
        }
        
    // Offer the menu to AIW first
    if (iAiwInterestArray->InitMenuPaneL(aResourceId, *aMenuPane, flags))
        {
        // No need to continue
        return;
        }

    if(aResourceId == R_PBK_GROUPSLIST_MENU)
        {
        if ( !Engine()->Constants()->
            LocallyVariatedFeatureEnabled( EPbkLVGroupManagementSend ) )
            {
            flags |= KPbkNoGroupSend;
            }
        CPbkMenuFiltering::GroupsListPaneMenuFilteringL(*aMenuPane, flags);
        }

    CPbkAppView::DynInitMenuPaneL(aResourceId,aMenuPane);
    }

TUid CPbkGroupsListAppView::Id() const
    {
    return CPbkAppUi::KPbkGroupsListViewUid;
    }

void CPbkGroupsListAppView::HandleStatusPaneSizeChange()
    {
    // Resize the container to fill the client rectangle
    if (iContainer)
        {
        iContainer->SetRect(ClientRect());
        }
    }

void CPbkGroupsListAppView::DoActivateL
        (const TVwsViewId& aPrevViewId,
         TUid aCustomMessageId,
         const TDesC8& aCustomMessage)
    {
    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkGroupsListAppView(%x)::DoActivateL()"), this);

    // Load the view status bar title
    HBufC* title = StringLoader::LoadLC(R_QTN_PHOB_TITLE);

    // Update application-wide state leave-safely
    CPbkAppUi::CViewActivationTransaction* viewActivationTransaction = 
        PbkAppUi()->HandleViewActivationLC(Id(), aPrevViewId, title, NULL);

    // Get the view state given as a parameter
    delete iParamState;
    iParamState = NULL;
    if (aCustomMessageId == CPbkViewState::Uid())
        {
        iParamState = CPbkViewState::NewL(aCustomMessage);
        }

    if (!iContainer)
        {
        // Create the control container
        CContainer* container = CContainer::NewLC(this, *this);

        container->SetHelpContext(
                TCoeHelpContext(ApplicationUid(), KPHOB_HLP_GROUP_LIST));

        if (!iViewExtension)
            {                  
            iViewExtension = iExtGlobal->FactoryL().CreatePbkViewExtensionL(
                    Id(), *PbkAppUi()->PbkDocument()->Engine());
            }
        
        // Create the view-side UI control and connect it to the container
        CPbkContactViewListControl* control = CPbkContactViewListControl::NewL(
            *Engine(), Engine()->AllGroupsViewL(), R_PBK_GROUPS_LIST_VIEW_CONTROL, container);

        container->SetControl(control, ClientRect());
        control->AddObserverL(*this);
        iViewExtension->SetContactUiControl(control);

        AppUi()->AddToStackL(*this, container);
        CleanupStack::Pop(container);
        iContainer = container;
        }

    // Activate the UI control
    iContainer->ActivateL();

    // Commit application-wide state changes
    viewActivationTransaction->Commit();
    CleanupStack::PopAndDestroy(2);  // viewActivationTransaction, title

    // PostCond:
    __ASSERT_DEBUG(iContainer, Panic(EPanicPostCond_DoActivateL));
    }

void CPbkGroupsListAppView::DoDeactivate()
    {
    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkGroupsListAppView(%x)::DoDeactivate()"), this);

    // Delete any previous control state
    delete iControlState;
    iControlState = NULL;
    delete iParamState;
    iParamState = NULL;

    if (iContainer)
        {
        // Remove view and its control from the view stack
        AppUi()->RemoveFromStack(iContainer);

        // Save UI control's state. Ignore errors because this function cannot 
        // leave and control state saving is not a critical operation.
        CPbkContactViewListControl* control = iContainer->Control();
        if (control)
            {
            TRAP_IGNORE(iControlState = control->GetStateL(EFalse));
            }

        // Destroy the container and the control
        delete iContainer;
        iContainer = NULL;
        }

    if (iViewExtension)
        {
        iViewExtension->SetContactUiControl(NULL);
        }

    // PostCond:
    __ASSERT_DEBUG(!iContainer, Panic(EPanicPostCond_DoDeactivate));
    }

void CPbkGroupsListAppView::HandleContactViewListControlEventL
        (CPbkContactViewListControl& aControl,
        const TPbkContactViewListControlEvent& aEvent)
    {
    __ASSERT_DEBUG(&aControl == iContainer->Control(),
        Panic(EPanicPreCond_HandleContactViewListControlEventL));

    switch (aEvent.iEventType)
        {
        case TPbkContactViewListControlEvent::EReady:
            {
            Cba()->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_EXIT);
            Cba()->DrawDeferred();
            aControl.RestoreStateL(iControlState);
            aControl.RestoreStateL(iParamState);
            delete iControlState;
            iControlState = NULL;
            delete iParamState;
            iParamState = NULL;
            break;
            }

        case TPbkContactViewListControlEvent::EItemAdded:
            {
            if (iGroupToFocus == aEvent.iContactId)
                {
                const TInt index = aControl.FindContactIdL(aEvent.iContactId);
                aControl.SetCurrentItemIndexAndDraw(index);
                iGroupToFocus = KNullContactId;
                }
            break;
            }

        default:
            {
            break;
            }
        }
    }

void CPbkGroupsListAppView::AiwCommandHandledL(TInt /*aMenuCommandId*/,
        TInt /*aServiceCommandId*/,
        TInt /*aErrorCode*/)
    {
    
    }
    
TPbkSendingParams CPbkGroupsListAppView::CreateWriteParamsLC()
    {
    // Construct the MTM filter
	CArrayFixFlat<TUid>* mtmFilter =
		new(ELeave) CArrayFixFlat<TUid>(4);
	CleanupStack::PushL(mtmFilter);

    const TUid KPostcardMtmUid = { KSenduiMtmPostcardUidValue };
    mtmFilter->AppendL(KPostcardMtmUid);	// hide postcard        

	TSendingCapabilities capabilities = TSendingCapabilities();
    capabilities.iFlags = TSendingCapabilities::ESupportsEditor;
	return TPbkSendingParams( mtmFilter, capabilities );
    }
    


//  End of File  
